pealdevDOCS
Back to peal.dev

STRIPE STARTER · PRICING UI

Pricing UI

PricingTable is the only component you need on your pricing page. It reads payment mode, hides the toggle for one-time, calculates yearly savings, highlights the popular plan. PricingCard and PricingToggle are its building blocks.

The pricing UI lives in src/components/pricing/. PricingTable is the orchestrator — drop it on a page and you have a working pricing section. The other two components (PricingCard, PricingToggle) are reusable pieces if you want to compose your own layout.

Drop-in usage

TSX
import { PricingTable } from "@/components/pricing/PricingTable";

export default function PricingPage() {
  return (
    <main className="py-24">
      <PricingTable />
    </main>
  );
}

What PricingTable does automatically

  • Reads payment mode via usePaymentsConfig().
  • Renders oneTimePlans, subscriptionPlans, or both — depending on mode.
  • Shows PricingToggle (monthly/yearly) only when subscriptions are supported.
  • Wires each card to CheckoutButton with the right Price ID for the current interval.
  • Calculates yearly savings via getYearlySavings() and badges it on the toggle.
  • Applies the "Most popular" treatment to whichever plan has highlighted: true.

usePricing — the interval toggle hook

TypeScript
import { usePricing } from "@/hooks/use-pricing";

const { interval, isYearly, isMonthly, toggleInterval } = usePricing();
// Pass `interval` to <PricingCard /> and <PricingToggle />.

Composing your own layout

If you want a non-grid pricing layout (a single hero card, a comparison table, etc.), skip PricingTable and use the primitives directly.

TSX
import { PricingCard } from "@/components/pricing/PricingCard";
import { PricingToggle } from "@/components/pricing/PricingToggle";
import { usePricing } from "@/hooks/use-pricing";
import { subscriptionPlans } from "@/config/pricing";

const { interval, toggleInterval } = usePricing();

<PricingToggle interval={interval} onToggle={toggleInterval} />
{subscriptionPlans.map((plan) => (
  <PricingCard key={plan.id} plan={plan} interval={interval} />
))}

Don't restyle by editing src/components/ui/*

Those files are generated by shadcn/ui. Edit them and the next time you bump a primitive you'll fight the diff. Wrap them in src/components/pricing instead.

Highlighting more than one plan looks weird

highlighted: true is meant for ONE plan — the one you want to nudge people toward. Marking two breaks the visual hierarchy. Pick one.