Pricing Plans
ComponentsPricing Plans
SectionsNew

Pricing Plans

A considered pricing section with monthly and annual billing, honest savings, and a clear next step for every plan.

USE IT FORSaaS pricingMembershipsService packages
React + CSS

folio®EXAMPLE WORKSPACE

ROOM TO GROW

Make room for more.

Starter

A little structure for your next big idea.

$12 / month

Billed monthly
  • 3 active projects
  • Your own workspace
  • Unlimited notes
Explore Starter

Scale

A shared home for a growing company.

$59 / month

Billed monthly
  • Unlimited projects
  • 20 team members
  • Workspace permissions
Explore Scale

Compare plans and see what’s included.

FOLIO / EXAMPLE PLAN DETAILS

Example plan details

Plan workspace

Live component. Go ahead, interact.
01

Installation

Run this in your shadcn-configured React project. The component and stylesheet are added together.

TERMINAL
npx shadcn@latest add http://localhost:5173/r/pricing-plans.json

This command uses the current site address. For localhost, keep this preview running on the same computer. Files follow your configured components alias.

02

Usage

Import the component and make the details your own.

TypeScript
import { PricingPlans } from '@/components/anticraft/PricingPlans';

export function Example() {
  return (
    <PricingPlans
      title="Make room for more."
      currency="USD"
      locale="en-US"
      plans={[
        {
          id: 'starter', name: 'Starter',
          description: 'A little structure for your next big idea.',
          monthly: 12, yearly: 120,
          features: ['3 active projects', 'Your own workspace', 'Unlimited notes'],
          href: '/signup?plan=starter', ctaLabel: 'Choose Starter',
        },
        {
          id: 'studio', name: 'Studio',
          description: 'More space for the work you do together.',
          monthly: 29, yearly: 288, featured: true,
          features: ['Unlimited projects', '5 team members', 'Shared project timelines'],
          href: '/signup?plan=studio', ctaLabel: 'Choose Studio',
        },
        {
          id: 'scale', name: 'Scale',
          description: 'A shared home for a growing company.',
          monthly: 59, yearly: 588,
          features: ['Unlimited projects', '20 team members', 'Workspace permissions'],
          href: '/signup?plan=scale', ctaLabel: 'Choose Scale',
        },
      ]}
    />
  );
}
03

Props

PropTypeDefaultDescription
plansPricingPlan[]RequiredPlan records with unique id, name, description, monthly and yearly amounts, a features string array, and a real href. An empty array renders nothing. Supply finite, nonnegative amounts in the currency’s main unit, for example 12 for twelve dollars.
plans[].monthly / yearlynumberRequiredThe actual monthly charge and the actual total annual charge. Yearly pricing displays the annual total with “/ year”, never an implied monthly equivalent. A positive annual saving is calculated from monthly × 12 minus yearly and rounded to the currency precision.
plans[].featuresstring[]RequiredVisible features included in that plan, rendered as a semantic list. Checkmarks are decorative; write clear feature descriptions.
plans[].href / ctaLabelstringRequired / 'Choose ' + nameA real signup, enquiry, or plan-detail destination and an optional visible link label. These remain ordinary anchors. Use onSelect in a Client Component if the destination needs the currently selected billing period.
plans[].featuredbooleanfalseHighlights a plan with a tinted background and a “A little more room” label. It does not change the order or select a plan for the visitor.
titlestring'A plan for your next chapter'The visible section heading and accessible section name.
currency / localestring'USD' / 'en-US'An ISO currency code and a locale accepted by Intl.NumberFormat. Explicit defaults keep formatting consistent between server and browser; the component does not detect a visitor’s location or convert currencies.
defaultBilling'monthly' | 'yearly''monthly'Initial billing period. Native pressed buttons switch the displayed prices and billing notes.
onBillingChange(period: BillingPeriod) => voidundefinedCalled when the visitor changes billing period. Pass callbacks from a Client Component when using a framework with a server/client boundary.
onSelect(plan: PricingPlan, period: BillingPeriod, event: MouseEvent<HTMLAnchorElement>) => voidundefinedReceives the selected plan, current billing period, and native React anchor event. Navigation continues unless your handler prevents it. Connect this to your own signup or checkout flow; the component does not collect payments.
classNamestring''Additional classes. Theme with --ac-pricing-surface, --ac-pricing-card, --ac-pricing-ink, --ac-pricing-muted, --ac-pricing-accent, --ac-pricing-featured, --ac-pricing-line, and --ac-pricing-font.
04

Motion & accessibility

Considered by default.

Monthly and Yearly are ordinary buttons with pressed states. Prices update in polite live regions; annual savings appear only when the annual total costs less than twelve monthly payments. Plan links remain keyboard and browser friendly. Below a 760px component width, cards become a touch-scrollable rail with scroll snapping; Tab brings each link into view. The rail keeps cards readable inside narrow sections. Reduced motion removes button and link transitions. The demo opens example plan details in a native dialog with Escape, focus containment, and focus restoration.

Use semantic content and meaningful labels in your composition. Check contrast and keyboard behavior with your own styles and content.