Pricing
Pricing sections: plan cards with a billing toggle, a comparison table, a seat picker, a single plan and a usage estimator.
Installation & usage
npx @youj/cli add marketing-pricingAlso installs badge, button, counter, icon-check, reveal, shimmer-border, table, toggle-group, use-controllable-state, youj-core, youj-ui-core.
The CLI copies the block to blocks/marketing/pricing.tsx with every component it uses, so it’s yours to edit.
Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:
'use client'
import Link from 'next/link'
import { Pricing, type PricingProps } from '@/blocks/marketing/pricing'
export function PricingView({ period, plans, comparison }: Pick<PricingProps, 'period' | 'plans' | 'comparison'>) {
return (
<Pricing
period={period}
plans={plans}
comparison={comparison}
copy={{ eyebrow: 'Pricing' }}
linkComponent={Link}
onPeriodChange={(period) => {
// your code
}}
onSelectPlan={(plan, period) => {
// your code
}}
/>
)
}Description
Plan cards with a monthly or yearly price toggle and a feature comparison under them. Prices roll to the new period, and on yearly the monthly price stands struck through beside each paid plan, so the toggle shows what it saves. Pick it for the usual tiered pricing page; this story opens on yearly billing.
A full feature table that keeps the plan prices and sign-up buttons in view as you scroll, with groups that fold away; the recommended plan's column carries its marks filled. Pick it when plans differ in many small ways.
Plan choice as radio cards beside an order summary that holds the seats and rolls the total as visitors choose. Pick it for per-seat pricing.
One plan with its price, the features it includes and a choice of currencies. Pick it when there is only one thing to buy.
Usage sliders and a cost breakdown that updates as visitors drag. Pick it for pay-as-you-go pricing.
Code
Pricing, the Plans story: the files youj add writes.
blocks/marketing
Reference
Props13 props, 3 types
Props
| Prop | Type | |
|---|---|---|
theme | ThemeInputDefault: the theme around it. The showcase passes the chosen preset here. | – |
embedded | booleanA section inside another page: the host lays it out (no page background, section padding or max width). default false | false |
defaultPeriod | PricingPeriod'monthly''yearly'The billing period shown first, when uncontrolled. default 'yearly' | 'yearly' |
period | PricingPeriod'monthly''yearly'The billing period shown, to control it. | – |
onPeriodChange | (period: PricingPeriod) => voidCalled when the visitor switches the billing period. | – |
plans | PricingPlan[]The plan cards, in order. default the demo's Hobby, Pro and Scale | the demo's Hobby, Pro and Scale |
comparison | PricingComparisonGroup[]The comparison table's groups, one value per plan in each row. An empty array hides the table. default the demo's three groups | the demo's three groups |
onSelectPlan | (plan: PricingPlan, period: PricingPeriod) => voidCalled when a plan's call to action is chosen, with the period shown. | – |
copy | Partial<PricingCopy>Any of the block's strings, to rewrite or translate. | – |
currency | stringThe currency prices are in (ISO 4217). default 'USD' | 'USD' |
locale | stringThe locale prices are formatted for (BCP 47). Default: the app's (YoujProvider's | – |
headingLevel | 1 | 2 | 3The section heading's level; plan names and the comparison title sit one below. default 2 | 2 |
linkComponent | LinkComponentThe element every internal link renders as, e.g. Next.js default 'a' | 'a' |
PricingPlan
| Prop | Type | |
|---|---|---|
idRequired | string | – |
nameRequired | string | – |
blurbRequired | stringOne line under the name. | – |
priceRequired | Record<PricingPeriod, number>The price per seat and month, when billed monthly or yearly. | – |
cta | PricingCtaThe plan's call to action; leave it out for none. | – |
featured | booleanLifted, with a traveling border light and the "Most popular" badge. | – |
featuresRequired | string[] | – |
PricingCta
| Prop | Type | |
|---|---|---|
labelRequired | string | – |
hrefRequired | string | – |
onClick | MouseEventHandler<HTMLAnchorElement> | – |
PricingComparisonGroup
| Prop | Type | |
|---|---|---|
groupRequired | string | – |
rowsRequired | { feature: string; values: PricingCell[]; }[] | – |
Strings17 keys for copy
Strings
copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.
eyebrowtitledescriptionperiodLabelmonthlyyearlysaveBadgemostPopularperUnitfreebilledMonthlybilledYearlymonthlyPricecompareTitlefeatureColumnincludednotIncludedBuilt from7 components
Built from
Components used
Accessibilitylandmarks, headings, controls, tables
Accessibility
Each section is a <section> named by its own heading (aria-labelledby); the heading is an h2 by default and headingLevel changes it.
Plans labels its billing period toggle and its “included” check marks, reads a struck-through monthly price as “billed monthly”, and each plan button is described by the plan it picks (aria-describedby). Seat picker is a radio group of plans, each named and described by its title and blurb, with a labelled period and plan selector. Compare is a real table with visually hidden text for the plan and feature columns, and its folding groups use aria-expanded and aria-controls. Usage estimator’s sliders are labelled and the new total is announced in a status region. Single plan’s currency choice is a labelled control.
The buttons and links are real a and button elements with the kit’s focus ring.