Page and route#
/components/button, rendered by ButtonGallery in apps/playground/src/app/components/button/gallery.tsx.
What the reader sees#
Seventeen small, focused demonstrations, each one card, each showing one facet of the kit's single button component: real product shapes first (a page-title action row, a card toolbar, table row actions, a form footer, a split-button export), then the raw prop surface (every color, every variant, every size, every named preset, async pending state, icon-only acknowledgement, corner badges, loading and disabled states, shade, and shape).
Layer 1: shell#
The playground's own navigation shell wraps this page like any other component page; there is no page-specific shell layer to describe. Button itself has no shell dependency; every example on this page renders standalone.
Layer 2: composition#
Same shared frame as every gallery page: PageFrame (button/gallery.tsx:35), ShowcaseTitle (:36), then a flat sequence of ExampleCards (:38-177), closing with a SlotMapCard (:179-186). The card order is deliberate, not alphabetical: the first six cards (page-title-actions, card-toolbar, row-actions-cluster, form-footer, export-split-button, link-buttons) are real product shapes lifted from shipping pages, and the remaining eleven are the prop-by-prop reference (colors, sizes, presets, promisify, IconOnClick, dropdown, badges, loading/skeleton/disabled, disabled-across-variants, shade, shapes). A reader skimming top to bottom sees "here is what it looks like in product" before "here is the whole knob set."
Layer 3: primitives#
| Primitive | Props as called | file:line | Contract doc |
|---|---|---|---|
PageFrame / ShowcaseTitle | the shared page frame and header | button/gallery.tsx:35-36 | shared across every playground page |
ExampleCard (×17) | title, subtitle, source/sourceTitle from src(name) (:29-32), each wrapping one example component; the second one also passes toolbar | button/gallery.tsx:38-177 | apps/playground/src/app/example-card.tsx |
Button (inside presets.tsx) | ten named presets mapped over one array, with Icon/content overrides only where the preset needs one | apps/playground/src/app/components/button/examples/presets.tsx:3-18 | packages/ui/docs/button.md |
Button (inside shapes-badge-sizing.tsx) | circle, dashed, badge/badgeClassName | apps/playground/src/app/components/button/examples/shapes-badge-sizing.tsx:8-12 | packages/ui/docs/button.md |
SlotMapCard | the four ButtonClassNames slot names | button/gallery.tsx:179-186 | apps/playground/src/app/slot-map-card.tsx |
Layer 4: patterns#
This page is one layer below the pattern layer, not an instance of a named pattern itself; it demonstrates the primitive the patterns are built from. The pattern pages that consume Button most directly are /patterns/job-title (a Button-driven copy affordance beside a page title), /patterns/bulk-selection-bar (the action bar's own buttons), /patterns/confirm-and-report (the modal footer's buttons, promisify-guarded per button.md:94-97), and /patterns/account-menu (a colorless sign-out button). None of those compositions are re-demonstrated here; this gallery stays at the single-component level throughout.
Layer 5: canon rules in force#
packages/ui/docs/button.md's own Banned section (:65-70) namesdropdown,promisify,bricked, andIconOnClickas implemented but with zero shipped call sites in either app; this gallery is where a reader actually sees them exercised (export-split-button.tsx,promisify.tsx,bricked-tooltip.tsx,icon-on-click.tsx). Demonstrating a cautioned prop on a component page is the intended use of that caution, not a lapse against it.docs/design-language/02-buttons-and-actions.md§A9, cited throughbutton.md:103-107: an icon-only button still needs a derived accessible name. Thecircleexamples inshapes-badge-sizing.tsx:8-9both carry an explicittooltipnaming what the demo shows ("circle", "circle lg"), satisfying the derivation chain even though these are documentation buttons with no realonClick.packages/ui/docs/card.md:11, 23: a card-scoped action belongs intoolbar, never a sibling div. The "Card toolbar actions" card (gallery.tsx, second card;examples/card-toolbar.tsx) demonstrates it twice over: theExampleCarditself carries aRight-arrow link to the Card page in itstoolbar, and the example inside renders a plainCardwhosetoolbarholds a shaded, toned action and an arrowed link.
Lapses#
Fixed 2026-08-17: the gallery now demonstrates a Button inside a Card's own toolbar slot. Until then none of the sixteen ExampleCards passed a toolbar prop, though packages/ui/docs/card.md:11, 23 and button.md's Travels-with section both name that composition as the one place a card-scoped action belongs, and the AppShell gallery (docs/breakdowns/05-kit-shell.md) exercised it while this page did not. The seventeenth card closes that loop; it was a coverage gap in the gallery's self-demonstration, never a defect in Button.
See also#
docs/breakdowns/05-kit-shell.md, whose own toolbar-button Lapses entry cites this gallery's contract doc from the other direction.packages/ui/docs/button.md, the contract every one of these seventeen cards demonstrates a slice of.packages/ui/docs/card.md, thetoolbarcontract this page's Lapses entry measures against.