# Pricing Table (Moonarc)

A feature-by-plan comparison: the highlighted plan's column lit, rows revealed with a 40 ms stagger as the table scrolls into view, and a header row that sticks when you cap the table's height. Semantic table, zero JavaScript of its own.

- Pro block. Install: `npx shadcn@latest add @moonarc-pro/pricing-table` (license key required)
- Tier B · category section · trigger scroll
- Readout: `<PricingTable plans={[…]} rows={[…]}>`
- Browser support: widely (every browser)
- Measured cost: 0 B JS of its own · uses Reveal + runtime (with dependencies 3.0 kB raw; CSS 9.9 kB raw)
- Page: https://moonarc.dev/components/pricing-table/

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `plans` | `{ name, price, highlight? }[]` | none | Columns. |
| `rows` | `{ feature, cells: (boolean | string)[] }[]` | none | Rows; true renders a check mark and false the word none (noneLabel), each with screen-reader text (includedLabel, excludedLabel); strings render as text. |
| `tone` | `'surface' | 'muted' | 'ink' | 'brand'` | `unset (paints nothing)` | The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. Each paints --background, --ma-tone-muted (over --muted, with a --border hairline), --ma-tone-ink or --ma-tone-brand (over --primary) with the matching text. With theme.css, a painted tone also re-declares --card, --border, --input and --ring inside the section, so cards and fields follow the ground. Decoration is strongest on brand. |
| `density` | `'compact' | 'cozy' | 'roomy'` | `'cozy'` | Cell padding ×0.8 / ×1 / ×1.25 through --ma-density. |
| `label` | `string` | `'Plans compared'` | Accessible name of the table, which scrolls sideways when a narrow screen cuts it: the section takes a tab stop, so a keyboard can reach and scroll it. |
| `featureLabel` | `string` | `'Feature'` | Screen-reader text of the feature column's header. |
| `includedLabel` | `string` | `'Included'` | Screen-reader text of a true cell. |
| `excludedLabel` | `string` | `'Not included'` | Screen-reader text of a false cell. |
| `noneLabel` | `string` | `'none'` | The word a false cell shows. |

## Usage

```astro
---
import PricingTable from '@/components/moonarc/pro/PricingTable.astro';
---
<PricingTable
  plans={[{ name: 'Starter', price: '$0' }, { name: 'Plus', price: '$120/yr', highlight: true }]}
  rows={[
    { feature: 'Projects', cells: ['3', 'Unlimited'] },
    { feature: 'Priority support', cells: [false, true] },
  ]}
/>
```

## Reduced motion

Rows fade in without stagger.

## With ClientRouter

Inherits Reveal; nothing to wire.

## Craft

- The markup is a <table>: screen readers get row and column headers, and the stagger is on the <tbody>.
- Stagger 40 ms: a table with 12 rows must finish inside half a second or it reads as loading.
- The highlighted column is a 6% tint of currentColor over the panel: visible in both themes, never a different colour.
- The section is its own scroll container (it scrolls sideways on a narrow screen), so the header row sticks inside it: give it a max-block-size (for example 80vh) and a long table scrolls under its plans.

## Replaces

- Comparison tables (Tailwind Plus)

## Source

Pro block. The source is served by the license-gated registry: `npx shadcn@latest add @moonarc-pro/pricing-table` with a key in components.json (https://moonarc.dev/account/). Everything it composes is free: reveal.
