/

Pricing Sections in React: Layouts That Do Not Get in the Way

The four pricing layouts that actually recur across 135 community components, the most-bookmarked example of each, and the mechanics a pricing section has to get right: billing toggles, comparable feature lists, currency and tax, and announcing a number that changes.

Serafim Korablev
Serafim Korablev
@korablev

A pricing section has one job: let someone find the plan that fits them and leave. Almost every one of them is one of four layouts (a row of plan cards, a feature comparison table, a single card when there is only one price, and an upgrade modal inside the product), and the layout is the easy part. What decides whether the page works is the mechanics underneath it: what the annual figure actually claims, whether the feature lists can be diffed at all, and whether the numbers announce themselves when someone flips the billing toggle.

There are 135 public components on 21st with "pricing" in the name. Below are the layouts that recur across them, the most-bookmarked example of each, and the things a pricing section has to get right regardless of which one you take.

Three cards in a row

The default, and it is the default for a mechanical reason: three columns is what fits a desktop row at a readable type size, and what stacks on a phone without turning into an endless scroll.

Pricing by Codehagen is the most saved pricing component on 21st with 2,363 bookmarks: three plans, a billing toggle, one card lifted out of the row. Pricing Section by UI Layouts (2,224) is the same skeleton with heavier borders and a tick list per plan.

The rest of this family differ mostly in density and tone:

The single card, and the card as a unit

If you sell one thing at one price, do not build a grid to hold it. Single Pricing Card by Efferd (584) is the whole section as one card: price, what is included, one button.

Separately, the card on its own is worth taking as a primitive rather than as a section. Pricing Card by 0xUrvish (616) and Pricing Card by Efferd (384) are single cards you map a plan array over, which is the shape you want when the plans come from Stripe rather than from a constant in the file.

The comparison table

Cards stop working when plans differ by more than a number. Pricing Section with Comparison by tommyjepsen (466) puts the cards on top and the full feature matrix underneath, which is the arrangement most B2B pricing pages converge on.

Worth knowing before you commit: a matrix with forty rows is a reference document, not a decision aid. It earns its place after the reader has narrowed to two plans, so keep the cards above it doing the first cut.

Pricing that moves

Pricing Interaction by LN (1,203) treats the billing toggle as the main event and animates the figures as they change. Creative Pricing by kokonutd (885) goes the other way, with a sketched, deliberately unpolished treatment.

Both are reasonable choices, with one caveat: pricing is the page where reading speed matters more than delight. A number that takes 400ms to settle is 400ms the reader spends waiting to compare it against the one next to it.

The upgrade modal

Modal Pricing by kokonutd (534) is the in-product version, and its context is genuinely different from the marketing page. The person already uses the product, already knows what the features do, and hit a limit thirty seconds ago. That argues for fewer plans on screen, the limit they hit named in the copy, and a way out that is not the browser back button.

The mechanics a pricing section has to get right

The toggle must say what it bills. If annual mode shows a per-month figure, the card has to state the billing terms next to it: the yearly total, and the fact that it is charged once. The reader will see that total at checkout, and the gap between the two numbers is where trust goes. Pick one presentation (per month billed annually, with the yearly total beside it, or the yearly figure directly) and keep the unit identical in both states, so the toggle changes the number and not what the number means.

Three columns is a layout constraint, not a pricing strategy. Four plans do not fit a desktop row at a readable size, which regularly leads teams to shrink the type or quietly drop a plan to make the grid work. Change the layout instead: a comparison table, a two-card row with enterprise as a wide banner underneath, or cards that wrap onto a second line. The plans should come from the business, the columns from the viewport.

The highlighted plan is a real nudge, so pick it on purpose. Whichever card you raise, badge or tint gets chosen more often than it otherwise would, which makes it a decision rather than a styling detail. Highlight the plan that fits the most people and that they will stay on, not the most expensive one. And if the badge says "Most popular", it should be true; "Recommended" is a claim about your own opinion, so it is always accurate and does the same job.

Feature lists should compare, not enumerate. The common failure is each column listing whatever that plan happens to include, in its own order and its own wording, which makes the columns impossible to diff. Build one canonical ordered list of features and give every plan the same rows with a value: a tick, a cross, a number, a limit. Keep excluded rows visible rather than dropping them, because a missing row reads as an oversight rather than as an exclusion. State limits as numbers ("3 seats", "10 GB") rather than comparatives ("more storage"), which mean nothing without the row above in view.

Say which currency, and say what the tax is. Put the currency next to the figure and state whether tax is included, near the price rather than in a footnote. Consumer pricing in the UK and the EU is normally displayed inclusive of VAT, while B2B pricing is usually quoted excluding it with tax added at checkout. If you pick a currency from the visitor's IP, give them a way to change it: the guess is wrong often enough (VPNs, travel, people living abroad) to generate support mail. If the charge is actually taken in a base currency and you display a converted figure, say so.

A toggle that changes numbers elsewhere has to announce itself. This is the accessibility case pricing sections most often fail. Use a real control rather than a styled div: the two options are mutually exclusive, so a radio group labelled "Monthly" and "Annual" usually reads better than a switch, because it names both states instead of one. When it changes, announce the change once through a small polite live region ("Annual billing, prices updated") rather than marking every card live, which would read every price aloud on each flip. Put the saving in text next to the option instead of signalling it only with a coloured badge, and make sure the new figure is legible without the animation, since a value that only exists mid-transition is invisible under prefers-reduced-motion.

Where else to look

Being honest about the alternatives, because the answer is not always us:

SourceBest forTrade-off
shadcn/uiCard, Switch, Tabs and Badge underneath your own layoutNo pricing block, so the composition and the billing logic stay yours
Tailwind PlusConventional marketing pricing sections, responsively testedPaid, and the layouts are recognisable because everyone uses them
Stripe pricing tablePlans that come from your Stripe catalogue and stay in sync with itAn embed configured in Stripe's dashboard, not a component you own
21stCommunity pricing sections and cards, previewable before you take oneQuality varies by author, and the plan data is static until you wire it up

The practical split: take the composition from wherever it already exists, keep the primitives underneath it consistent with the rest of your app, and treat the plan data as your own concern rather than the component's.

Taking one

Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:

bash

The key comes from your 21st account, and installs need a membership, so this is not a free copy and paste. Set API_KEY_21ST once in your shell and the same command works for anything in the catalogue. If you would rather not leave your editor, the 21st MCP does the same thing from Claude, Cursor or Codex: ask for a pricing section, get previews inline, and have the agent write the file.

Browse pricing sections →

Frequently asked

What should a pricing section include?
For each plan: a name, the price with its billing terms stated in full, a feature list, and a single action. The feature list is the part most pages get wrong. Every plan should show the same ordered rows with a different value in each, a tick, a cross, a number or a limit, rather than each column listing whatever that plan happens to include in its own order and wording, because columns written that way cannot be compared at a glance.
Should a pricing page default to monthly or annual prices?
Either default is defensible, and it depends on which billing period most of your customers actually choose. What matters more is that the annual state says what it bills: showing a per-month figure under annual billing is fine only when the yearly total and the fact that it is charged once appear next to it. The reader will see that total at checkout, and the gap between the two numbers is where trust is lost.
How do you make a monthly and annual pricing toggle accessible?
Use a real control rather than a styled div. The two options are mutually exclusive, so a radio group labelled with both billing periods usually reads better than a switch, which names only one state. Announce the update once through a small polite live region instead of marking every price card live, which would read every figure aloud on each flip, and put the annual saving in text next to the option rather than signalling it only with colour.
How many pricing components are on 21st?
135 public components have pricing in the name as of August 2026, covering three-column card rows, feature comparison tables, single cards, standalone plan cards you map your own data over, and in-app upgrade modals. Each one has a live preview on its page, and they are browsable at 21st.dev/community/components/s/pricing-section.

Published

Aug 19, 2026

Read time

6 min

Tags

GuidePricingConversion

Share