Specimen
StableOne part on a quiet raised card. Specimen captions it underneath; Figure titles it on top.
Specimen is how the kit pages show each part on its own: a raised card at least 144 pixels tall that centres what you put in it, with a mono label and an optional note below. Figure, from the icon pages, puts the caption on top (label, title and note) for diagrams that need a word before they are looked at.
Updated View source
Specimens in a grid
import { useState } from 'react'import { Specimen } from '@rchursin/product/shell/layout'import { Button, Chip, KeyCombo, Switch } from '@rchursin/product/ui'
/** One part per card, named underneath. The caption is the figure's <figcaption>. */export default function SpecimenGrid() { const [sync, setSync] = useState(true) return ( <div className="grid w-full grid-cols-1 gap-x-5 gap-y-8 sm:grid-cols-2"> <Specimen label="Button · primary" note="One per view, for the main action."> <Button icon="plus">New task</Button> </Specimen> <Specimen label="Switch" note="Takes effect at once; no Save button."> <Switch label="Sync calendar" checked={sync} onChange={setSync} className="w-full max-w-56" /> </Specimen> <Specimen label="Chip · four shapes" note="Kinds told apart by shape, not colour." bodyClassName="flex-wrap gap-2"> <Chip variant="solid">Solid</Chip> <Chip>Outline</Chip> <Chip variant="muted">Muted</Chip> <Chip variant="dashed">Dashed</Chip> </Specimen> <Specimen label="Key combo" note="“mod” is ⌘ on Apple keyboards, Ctrl elsewhere."> <KeyCombo combo="mod+k" /> </Specimen> </div> )}Usage
import { Specimen } from '@rchursin/product/shell/layout'import { Figure } from '@rchursin/product/iconset/parts'<Specimen label="Button · primary" note="One per view."> <Button>Save changes</Button></Specimen>Examples
Figure
The caption comes first: a label, a title and a note, then the diagram.
import { Icon } from '@rchursin/product/icons/Icon'import { Figure } from '@rchursin/product/iconset/parts'
const sizes = [16, 20, 24, 32]
/** Figure puts the caption on top: a label, a title and a note, then the diagram. */export default function SpecimenFigure() { return ( <Figure label="Sizes" title="One icon, four sizes." note="Drawn on a 24 grid with a single 1.5 stroke. At 16 pixels the stroke is exactly one pixel wide." className="w-full max-w-xl" > <ul className="grid grid-cols-2 gap-3 sm:grid-cols-4"> {sizes.map((px) => ( <li key={px} className="flex flex-col items-center gap-3 rounded-xl bg-fg/[0.035] py-5 ring-1 ring-line ring-inset"> <Icon name="calendar" size={px} /> <span className="font-mono text-[11px] text-fg-3 tabular-nums">{px} px</span> </li> ))} </ul> </Figure> )}API
Specimen props
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | – | The mono caption under the card, e.g. "Switch · off". |
note | ReactNode | – | One line under the label: the thing to know about this part. |
childrenrequired | ReactNode | – | The part, centred on the card. |
className | string | – | Extra classes on the <figure>. |
bodyClassName | string | – | Extra classes on the card, e.g. "flex-wrap gap-2" or "justify-start". |
Figure props
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | – | The mono label at the top. |
titlerequired | string | – | One line that says what the figure shows. A <span>, not a heading. |
note | ReactNode | – | A sentence or two under the title. |
childrenrequired | ReactNode | – | The diagram, under the caption. |
className | string | – | Extra classes on the <figure>. |
style | CSSProperties | – | Inline styles, e.g. style={delay(1)} to stagger its arrival. |
Accessibility
- Both render a <figure> with a <figcaption>, so the caption names the figure for screen readers.
- Figure’s title is a <span>, not a heading: it doesn’t appear in the page outline. Put a heading before it if people need to jump to it.
- The card has no role and isn’t focusable; the part inside keeps its own roles and keyboard behaviour.
- Both carry lux-reveal: inside a root that calls useLuxe they arrive as they scroll in; with reduced motion they are simply there.
Guidelines
Do
- Show one part, or one part in a few states, per specimen.
- Name the part and its variant in the label: “Button · primary”.
- Use the note for the one thing to know about it.
Don’t
- Don’t put a whole tool in a specimen; give it an AppWindow.
- Don’t rely on the caption to label a control inside; the control needs its own name.
In use
Used on this site
Related
- SectionA page band with an eyebrow, an h2 and a lead, on a plain or sunken ground. SectionHeading is the heading block alone.
- App windowThe RChursin_ app frame: a sidebar with the tools, a title row with a toolbar, and your tool in the body.
- Cards & elevationCards on one four-step elevation scale: lux-card, a lower lux-card-flat, lux-lift on hover and lux-float for overlays.
- Do and don’tA do / don’t pair: two cards side by side with a short note each, told apart by icon, word and a dashed edge.
Source
The component’s own files, exactly as they run on this site.
/** * Layout pieces for the kit pages: an intro, numbered sections, specimens (one component on a * card with a caption), a keyboard table and a short list of rules. * They share the site's finishing layer: arrivals (lux-reveal), hairlines, grain, the halo. */import type { ReactNode } from "react"import { cx } from "../../components/cx"import { useLuxe } from "../../components/motion"import { delay } from "../../home/ui"import { KeyCombo } from "../ui/button"
export function KitPage({ children, className }: { children: ReactNode; className?: string }) { const root = useLuxe<HTMLDivElement>() return ( <div ref={root} className={cx("bg-surface text-fg antialiased", className)}> {children} </div> )}