Progress
LoadingA bar that fills to its value when it scrolls into view, with the number counting up beside it, or a ring with the number in the middle.
Compares your product with others in an "us versus them" table. The first column is highlighted, rows reveal with a stagger, and a thin bar under each numeric cell shows a byte count or a score at a glance. A semantic table with zero JavaScript of its own.
| Moonarc Pro | React Bits Pro | Aceternity | |
|---|---|---|---|
| Astro without a React island | yes (better) | no | no |
| Measured JS cost per component | yes, in CI (better) | no | no |
| Tools that run on your repo | audit + measure (better) | no | no |
| WebGL spectacle | 11 so far, each tested for leaks and lost contexts | far more (better) | some |
| Fixed catalogue, one payment | Founding 200 only | $129–349 once | $199 once, better if that is all you want (better) |
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
JavaScript of its own
0 B
Uses Reveal and the shared runtime (1.9 kB raw, once per site). With those included: 3.0 kB raw.
CSS 12.0 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 85 · Firefox 128 · Safari 16.4; needs property. Elsewhere: bars fill without animating.
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
npx shadcn@latest add @moonarc-pro/compare-table---
import CompareTable from '@/components/moonarc/pro/CompareTable.astro';
---
<CompareTable
columns={['Ours', 'Product A', 'Product B']}
max={10}
rows={[
{ label: 'Setup steps', cells: [{ text: '2', value: 2, good: true }, { text: '9', value: 9 }, { text: '6', value: 6 }] },
]}
/>Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: reveal, progress.
| Prop | Type | Default | Description |
|---|---|---|---|
columns | string[] | none | Column headers; the first is "us". |
rows | { label, cells: { text, value?, good? }[] }[] | none | Rows; a numeric value draws a bar; good bolds the cell and adds goodLabel for screen readers. |
max | number | 100 | Maximum for the bars, shared by every row. |
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 | 'Comparison' | 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. Make it unique per page. |
goodLabel | string | 'better' | Screen-reader text after a good cell's text, in parentheses, since bold alone says nothing to a screen reader. |
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
.ma-compare.ma-compare__bar.ma-compare__copy.ma-compare__eyebrow.ma-compare__head.ma-compare__headline
slot="eyebrow"slot="headline"slot="copy"
Rows fade in without stagger; bars are full at once.
ClientRouterInherits Reveal and Progress; nothing to wire.
Replaces: Comparison sections (Tailwind Plus). See the migration table.
A bar that fills to its value when it scrolls into view, with the number counting up beside it, or a ring with the number in the middle.
Entrance on scroll that plays once and stays, staggers its children, scrubs with the scroll position when asked, honours reduced motion, and keeps working after every ClientRouter navigation.
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.
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown