React Pricing Comparison Table with Grouped Features and a Billing Switch

Pro

Plans across the top with their name, a tagline and a price per user per month; feature rows grouped under headings such as Usage, Essentials and Advanced underneath. A switch at the top left flips every price between annual and monthly, and the numbers count to their new value. One plan can be flagged with a coloured corner.

Comparison Section With Simple Pricing block preview

Pricing and features on one grid

Comparison Section with Simple Pricing is a React and Tailwind CSS pricing comparison table that combines plan prices, a billing switch and grouped feature rows in one grid, with soft colour washes down each column. It runs in Next.js or any React app with Framer Motion.

Many sites split pricing cards and the feature table into two sections, which makes buyers scroll back up to remember a price. Keeping the price at the top of each column of the table means the number and everything it buys stay in view together.

Groups keep long feature lists scannable. Rather than forty rows in a row, each group has a label, so a buyer looking for security features or usage limits can find the right block at once.

What the grid contains

Header corner

The heading and a Pay annually or Pay monthly switch with role switch sit in the top left cell.

Plan header

Name, tagline, price, user per month, a billed annually note in annual mode and a link styled call to action.

Column washes

A sky or sand tint runs the full height of a plan's column so the eye can follow it down.

Flag

A flagged plan gets a coloured triangle in its corner, a quieter alternative to a Most popular badge.

Counting prices

Switching billing animates each price between values with a short count, instant for reduced motion.

Grouped rows

Rows sit under group labels. Cells show a check, a short text value or a cross labelled Not included.

When to merge pricing into the table

Use it when

  • You prefer a subtle corner flag to a loud Most popular badge.
  • Per seat pricing with an annual discount.
  • Long feature lists that benefit from grouping.
  • Three or four plans that buyers compare carefully.
  • You want a softer, less boxy table with colour washes.

Skip it when

  • Screen reader navigation by row and column is a requirement; the grid is not table markup.
  • Phone visitors are the majority. The grid is 920px wide and scrolls sideways.
  • Your prices are flat rather than per user; the user per month label would need editing.
  • You want a large button per plan; calls to action are link styled.

Plans, groups and rows

plans takes an id, name, tagline, monthly and annualMonthly prices, a cta label, optional href, a wash of sky or sand and an optional flagged boolean. groups takes an id, label and rows, and each row has an id, label and values keyed by plan id, where a value is true, false or a short string.

Both prices are written per plan, so you control rounding exactly. Keep text values short, such as 10 GB or Unlimited, because the columns are narrow.

npx wensity@latest add comparison-section-with-simple-pricing --type block
page.tsx
import { SimplePricingComparison } from "@/components/wensity/blocks/comparison-section-with-simple-pricing";
export function Pricing() {
return (
<SimplePricingComparison
heading="Plans and limits"
plans={[
{ id: "basic", name: "Basic", tagline: "Small teams", monthly: 12, annualMonthly: 10, cta: "Start trial", href: "/signup", wash: "sky" },
{ id: "business", name: "Business", tagline: "Growing teams", monthly: 24, annualMonthly: 20, cta: "Start trial", href: "/signup?plan=business", wash: "sand", flagged: true },
]}
groups={[
{
id: "usage",
label: "Usage",
rows: [{ id: "storage", label: "Storage", values: { basic: "50 GB", business: "1 TB" } }],
},
{
id: "security",
label: "Security",
rows: [{ id: "sso", label: "Single sign on", values: { basic: false, business: true } }],
},
]}
/>
);
}

Props

PropTypeDefaultDescription
plans{ id; name; tagline; monthly; annualMonthly; cta; href?; wash?; flagged? }[]-Columns with both prices. wash tints the column; flagged adds the corner mark.
groups{ id; label; rows: { id; label; values }[] }[]-Labelled blocks of feature rows.
headingstring"Simple pricing"Shown in the top left cell above the switch.

Strengths and limits

Both themes

The sky and sand washes have dark counterparts, deep blue and deep brown, and the corner flag keeps its orange in both modes.

Grid, not table

The layout is CSS grid. Screen readers read it cell by cell without row and column headers; convert to a table if that matters.

Labelled crosses

Excluded features carry a Not included label, so absence is announced rather than silent.

Reduced motion

The price count is instant for visitors who prefer reduced motion.

Accessible switch

The billing control uses role switch with its state exposed.

Sideways scroll

Below 920px the grid scrolls horizontally. Add a visual hint, or show stacked plan cards on phones.

Block details

Comparison Section With Simple Pricing
Renders
CSS only. Paints as soon as the stylesheet arrives
Theme
Follows the site theme in light and dark
Dependencies
clsxframer-motiontailwind-merge
Source
386 lines, 12 KB in one file
Install
wensity add comparison-section-with-simple-pricing --type block
Tags
light, dark, comparison, pricing, toggle, checks
Last updated

Alternatives with different trade offs