Pricing Cards Section React component
A per-seat pricing section: a team size slider, monthly or yearly billing and a currency picker that recalculate every card's seat price and monthly total as they count, plans that grey out when the team is too big, and a compare all features table that opens below.
About the Pricing Cards Section component
Pricing Cards Section is a pricing block for products sold per seat. Visitors set their team size with a slider, pick monthly or yearly billing and a currency, and every card shows the seat price and the monthly total for that team, counting smoothly to the new numbers.
Plans can have a seat limit: when the team is bigger, the card fades, says why and disables its button. A Compare all features button opens a grouped table under the cards with checks, dashes and short values such as storage.
When to use it
Use it on the pricing page of a SaaS product that charges per user or seat.
For flat plan prices without seats, the Pricing Table component is simpler.
Installation
Add the Pricing Cards Section component to your project with the shadcn CLI. It lands in components/pricing-cards-section.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/pricing-cards-sectionOr copy the source by hand and install its dependencies:
npm install motion clsx tailwind-mergeProps
<PricingCardsSection /> accepts 13 props, all optional.
| Prop | Type | Default |
|---|---|---|
| eyebrow | string | "Pricing" |
| title | string | "Pay for the seats you use" |
| description | string | "Every plan includes unlimited projects and guests. Change seats any time; we prorate the… |
| plans | PricingCardPlan[] | DEFAULT_PLANS |
| comparison | { group?: string; feature: string; values: (boolean | string)[] }[] | DEFAULT_COMPARISON |
| currencies | { code: string; symbol: string; rate: number }[] | DEFAULT_CURRENCIES |
| defaultBilling | "monthly" | "yearly" | "yearly" |
| defaultSeats | number | 8 |
| seatLimit Highest value on the seat slider. | number | 100 |
| yearlyNote Shown next to the Yearly option. | string | "2 months free" |
| onSelect | (selection: PricingSelection) => void | — |
| theme | "dark" | "light" | "dark" |
- eyebrowstringDefault: "Pricing"
- titlestringDefault: "Pay for the seats you use"
- descriptionstringDefault: "Every plan includes unlimited projects and guests. Change seats any time; we prorate the…
- plansPricingCardPlan[]Default: DEFAULT_PLANS
- comparison{ group?: string; feature: string; values: (boolean | string)[] }[]Default: DEFAULT_COMPARISON
- currencies{ code: string; symbol: string; rate: number }[]Default: DEFAULT_CURRENCIES
- defaultBilling"monthly" | "yearly"Default: "yearly"
- defaultSeatsnumberDefault: 8
- seatLimit
Highest value on the seat slider.
numberDefault: 100 - yearlyNote
Shown next to the Yearly option.
stringDefault: "2 months free" - onSelect(selection: PricingSelection) => void
- theme"dark" | "light"Default: "dark"
Show all 13 propsShow fewer
| className | string | — |
- classNamestring
npm dependencies
Installed for you by the shadcn CLI.
Pricing Cards Section FAQ
- How are the prices calculated?
- Each plan has price.monthly and price.yearly as the per-seat monthly price in your base currency. The card shows that price times the currency rate, and the total is that times the seats. Set price to null for a Custom enterprise plan.
- Can I use real exchange rates or my own prices per currency?
- Pass currencies with the rate you want, for example { code: "EUR", symbol: "€", rate: 0.92 }. For fixed local prices, keep one currency and render one section per region, or round the rate so prices land on the numbers you want.
- What happens when the team is bigger than a plan allows?
- Give the plan maxSeats. Above that number the card fades to 55%, shows 'Up to N seats' and its button is disabled, so people are steered to a bigger plan.
- How do I send people to checkout?
- Give each plan an href, or handle onSelect, which receives the plan id, billing period, seats, currency and monthly total, and redirect from there.
- Can I hide the comparison table or the currency picker?
- Pass comparison={[]} to hide the table and a single currency to hide the picker. seatLimit sets the highest value on the slider.