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
Plans differ by features or limits
A structured card grid makes equivalent features, units, and exclusions easier to compare across tiers.
Billing periods can be changed
Use a labeled switch only when monthly and annual amounts, units, savings language, and checkout parameters update together.
Purchase details need progressive disclosure
Keep the primary comparison visible and move longer billing, cancellation, or usage explanations into accessible disclosures.
Pricing Sections to explore
Open a component page to inspect its live example, editable source, installation command, dependencies, API details, accessibility notes, and related components.
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 buttonimport { 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>
);
}Linked guides
Spacing systems for UI
Keep repeated plan content aligned without relying on fixed card heights.
GuideCommon UI and UX mistakes
Avoid ambiguous actions, hidden costs, and inconsistent comparison rows.
GuideForms that do not get in the way
Carry the selected plan into a clear checkout or contact flow.
Related topic guides
Pricing Sections questions
No. Pricing components are interface source. Your application remains responsible for products, prices, checkout, taxes, entitlements, and subscription lifecycle events.