# Plan comparison

A React block (a whole screen) in [Beamline](https://beamline.io/)'s [Blocks](https://beamline.io/components/blocks) category. Live demo: https://beamline.io/components/plan-comparison

Plans side by side against every feature: prices that roll between monthly and yearly, the current and recommended plan marked, a header that stays in view while the features scroll, differences only, and included, not included and not specified told apart.

## Use it for

- An upgrade or pricing page where people compare plans feature by feature before choosing.

## Not for

- Choosing a plan inside a checkout or settings form ([radio-cards](https://beamline.io/components/radio-cards)).
- Showing what the current plan uses ([usage-meter](https://beamline.io/components/usage-meter)).

## Anatomy

- title and description
- billing period toggle (savings note)
- differences-only switch
- plan picker (narrow screens)
- sticky plan header (name, badges, price, period line, call to action)
- feature groups (group row, feature rows with an optional hint)
- cell: included (check) · not included (—) · a value · not specified (hatched)

## Variants

- **period**: monthly, yearly

## States

- monthly / yearly (prices roll)
- current plan (badge, its button says so)
- recommended plan (accent edge, badge, accent button)
- choosing (the plan's button busy, the others wait)
- choice failed (message under the button)
- differences only (equal rows hidden; nothing left says so)
- quote-only plan (Talk to sales)
- free plan
- narrow: one plan at a time with a picker; its header spans the row (name, price and button at full width)
- header stuck (hairline shadow)

## Keyboard

- Tab: period toggle, differences switch, plan picker (narrow), each plan's button, then each feature hint
- arrow keys move within the period toggle and the plan picker
- hints open on focus and close with Escape

## Motion

Prices roll digit by digit when the period changes (slot text); the stuck header gains its shadow over --motion-in. Reduced motion swaps prices at once.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `plans` (required) | `PlanComparisonPlan[]` | — | id, name, description, price { monthly, yearly } per unit per month (null = quoted by sales, 0 = free), unit, cta. |
| `groups` (required) | `PlanFeatureGroup[]` | — | Feature groups; each feature has values per plan id: true (included), false (not included), a string or number, or null (not specified). |
| `period / defaultPeriod / onPeriodChange` | `"monthly" \| "yearly"` | `"yearly"` |  |
| `currentPlan` | `string` | — | The plan the account is on. |
| `recommendedPlan` | `string` | — |  |
| `onSelectPlan` | `(planId, period) => void \| Promise<void>` | — | A plan's button; a promise shows progress on it and a rejection shows its message. |
| `differencesOnly / defaultDifferencesOnly / onDifferencesOnlyChange` | `boolean` | — |  |
| `format` | `(amount: number) => string` | — | Price formatting. Default whole US dollars. |
| `title / description` | `ReactNode` | — |  |
| `unknownLabel` | `string` | `"Not specified"` |  |
| `stickyOffset` | `number` | `0` | Pixels from the top of the scroller where the header sticks (below your own app bar). |
| `className` | `string` | — |  |
| `classNames` | `PlanComparisonClassNames` | — |  |
| `style / ref` | `CSSProperties / Ref<HTMLDivElement>` | — |  |

## Built from

- [billing-toggle](https://beamline.io/components/billing-toggle)
- [slot-text](https://beamline.io/components/slot-text)
- table
- button
- badge
- switch
- tooltip
- [segmented-control](https://beamline.io/components/segmented-control)
- [empty-state](https://beamline.io/components/empty-state)

## Dependencies

`lucide-react`, `motion`

## Import

```tsx
import { PlanComparison } from "@/blocks/plan-comparison/plan-comparison";
```

## Get it

Plan comparison is part of Beamline: 190 React components and screens your coding agent (Claude Code, Codex, Cursor or any MCP client) installs into your app through Beamline's MCP server, as a ready-built package or as plain React source you can change. $49 one payment (regular $200), no subscription, a year of updates, one licence for your whole team. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in Blocks

- [AI agent workspace](https://beamline.io/components/agent-workspace): Threads, a conversation with streamed reasoning, cited answers and a plan that waits for approval then runs step by step, and an artifacts panel with…
- [Analytics dashboard](https://beamline.io/components/analytics-dashboard): A SaaS overview in the app shell, fed by your metrics hook: range and segment filters drive KPIs, new and expansion revenue, channels, plan mix, uptime…
- [Auth page](https://beamline.io/components/auth): The whole sign-in / sign-up route: product mark, a quiet dotted field with a light that follows the mouse, an optional notice, the SignIn and SignupForm…
- [Changelog feed](https://beamline.io/components/changelog-feed): An in-app What's new page: release notes grouped by month with tags, versions, pictures and details, a tag filter with counts, entries since your last…
- [CRM pipeline](https://beamline.io/components/crm): A pipeline screen: KPIs and stage mix derived from a virtualised deals grid with inline edit, bulk moves and delete with undo; a row opens the deal in a…
- [Empty states](https://beamline.io/components/empty-states): The five empty moments every product has, written and wired: first use with a first step, no results with the filters to clear, an error with retry and a…
- [Page header](https://beamline.io/components/page-header): The top of a record or project page: breadcrumb, title with status, description and meta, a primary action with secondary actions that fold into a More…
- [Settings](https://beamline.io/components/settings): Profile and workspace settings with one draft and real save handler. Personal mode omits workspace data; optional profile fields share validation…
- [Sign in](https://beamline.io/components/sign-in): The sign-in card: email and password, a one-time code or a magic link, passkeys and single sign-on, with validation, progress, errors and a signed-in…
- [Sign up form](https://beamline.io/components/signup-form): The account creation card: single sign-on, name, work email and a password with strength and Caps Lock hints, terms consent, inline validation, your…
- [Step form](https://beamline.io/components/step-form): The finished frame for any multi-step form you compose — onboarding, intake brief, questionnaire, booking, application: a wide card with progress, the…
- [Trading terminal](https://beamline.io/components/trading-terminal): A perpetuals terminal on your feed and your account: ticker tape, market header with funding, candles, book / trades / depth, order ticket, account…
- [Voice agent](https://beamline.io/components/voice-agent): A voice agent in three layouts on one session: a support panel that mixes typing and talking, a call screen with the agent's orb and one call button, and…
