Skip to main content
Different job from <SubscriptionCard>: that one is a settings control for someone who already has an account (“here’s what you can move to”). <PricingTable> is the page that sells - plan cards, a monthly/annual toggle, and a checkout button, built from whatever you’ve configured in Catalog.
That’s a complete pricing page: the toggle only appears if you actually sell more than one price label, and switching it animates the price rather than swapping it instantly. Clicking a plan checks out a new subscriber directly. For someone already subscribed, it opens a confirmation panel first, then swaps the plan in place (changePlanPrice()) instead of starting a second checkout — Stripe have no notion of “replace my existing subscription”, so a fresh checkout session there would create a second, independent one rather than replacing the first. onSelectPlan overrides this whole flow, confirmation included, when you want your own.

Building your own layout

<PricingTable.Plans> is a shortcut in a responsive grid. Skip it and place <PricingTable.Plan> yourself for a custom layout - a plan featured in the middle, a two-column comparison, a page that sells just one plan:
featured and badge are yours to set - neither is inferred from the plan itself. A plan’s is_default means “the free tier a signup falls back to with no subscription,” not “recommended,” so nothing here derives a badge from data.

Reference

Going fully custom

usePricingTable() gives you the same state the components above read, for a page that doesn’t use them at all:
Must be called somewhere under <PricingTable> - it reads the same provider <PricingTable.LabelSwitch>/<PricingTable.Plan> do. Formatting a price is more than ${amount}: a label’s display_interval needs converting (an annual price shown at its monthly cost), and the amount needs locale-aware currency formatting. Reuse the same helpers the built-in card uses instead of redoing that arithmetic:
formatInterval, formatDate, formatNumber, humanizeFeatureKey, collectPriceLabels and resolveLabelSavings (the “Save 20%” hint on a label switch) are exported from @kerne/react/ui the same way.