Developer guide

React pricing sections with clear plan comparison

A pricing section presents plan differences, billing units, included limits, and the next purchase or contact action. This guide shows how Spectrum UI card, button, status, quantity, disclosure, and switch components can be composed into an understandable React pricing interface.

The UI does not create products, prices, checkout sessions, taxes, or subscription state. Load authoritative plan data from your application and keep the displayed amount, billing period, and action destination consistent.

What Pricing Sections means

Pricing is structured product information, not just a row of decorative cards. Users need to compare equivalent attributes, understand recurring periods and usage limits, and identify which action begins checkout versus a sales conversation.

Use local cards for plan structure, buttons for explicit actions, accordions for secondary policy details, and switches only when every displayed amount updates together. A recommended-plan treatment should reflect a real product decision rather than an arbitrary visual default.

When to use these patterns

01

Plans differ by features or limits

A structured card grid makes equivalent features, units, and exclusions easier to compare across tiers.

02

Billing periods can be changed

Use a labeled switch only when monthly and annual amounts, units, savings language, and checkout parameters update together.

03

Purchase details need progressive disclosure

Keep the primary comparison visible and move longer billing, cancellation, or usage explanations into accessible disclosures.

Render plan data with local card primitives

The plans stay as data, while the Card and Button primitives provide the visible comparison and action.

pnpm dlx shadcn@latest add card button
PricingGrid.tsx
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';

const plans = [
  { name: 'Starter', price: '$12', summary: 'For one product workspace' },
  { name: 'Team', price: '$29', summary: 'For collaborative product teams' },
];

export function PricingGrid() {
  return (
    <div className="grid gap-4 md:grid-cols-2">
      {plans.map((plan) => (
        <Card key={plan.name}>
          <CardHeader>
            <CardTitle>{plan.name}</CardTitle>
          </CardHeader>
          <CardContent>
            <p className="text-3xl font-medium">{plan.price}/month</p>
            <p className="mt-2 text-muted-foreground">{plan.summary}</p>
            <Button className="mt-6 w-full">Choose {plan.name}</Button>
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

Pricing Sections questions

No. Pricing components are interface source. Your application remains responsible for products, prices, checkout, taxes, entitlements, and subscription lifecycle events.