crucıble

Touchstone

Feature comparison matrix in two modes — plans (3–4 pricing columns) or versus (your product framed in the accent against alternatives). Collapsible row groups, a sticky name/price/CTA header that frosts once pinned, checks that draw in row by row, row hover with floating hints, column-header dimming, and a one-column view with a segmented picker and swipe under 640px. Real table semantics.

motionpro

Installation

CLI

npx shadcn@latest add @crucible/touchstone

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
mode"plans" | "versus""plans""plans" compares 3–4 pricing plans; "versus" compares your product (the highlighted column) against 2–3 alternatives. Also picks the sample data when columns/groups are omitted.
columnsTouchstoneColumn[]Column definitions. Omit for sample data matching mode.
groupsTouchstoneGroup[]Grouped feature rows. Omit for sample data matching mode.
eyebrowReact.ReactNodeSmall label above the title. Pass null to hide.
titleReact.ReactNodeSection heading. Pass null to hide the header block.
subtitleReact.ReactNodeSupporting line under the title.
footnoteReact.ReactNodeMuted footnote beside the legend.
defaultCollapsedstring[][]Group labels collapsed on first render.
onGroupToggle(label: string, open: boolean) => voidFires when a group is expanded or collapsed.
onColumnChange(index: number) => voidFires when the narrow-view column changes (picker or swipe).
stickyOffsetnumber0Distance from the top of the scroll container where the column header pins, in px (e.g. a fixed navbar).
accentColorstring"#e9c46a"The single signature accent — highlight frame, checks in the highlighted column, primary CTA, focus rings.
refReact.Ref<TouchstoneHandle>Imperative handle (replay(), expandAll(), collapseAll(), showColumn()). React 19 ref-as-prop.
classNamestringExtra classes for the <section> root.
Also accepts all props of Omit<React.ComponentPropsWithoutRef<"section">, "children" | "title"> — they pass through to the underlying element.

Honors prefers-reduced-motion with a designed static fallback, and passes className through.