Button
Hero — hover or focus any button
All seven states — click a chip to see each one
When to use
<Button> is Matter's canonical button primitive. Reach for it for any
clickable affordance — CTAs, form submissions, navigation triggers,
dialog openers. The five variants carry distinct visual weight; the
seven sizes carry distinct geometric weight. Pick variant by hierarchy,
size by surface density.
asChild to wrap a <Link> when the button is navigation: <Button asChild><Link href="/x">Go</Link></Button>..bloom-* / .glow-* class so --btn-glow inherits correctly.Anatomy
A single root element (a <button> by default, or whatever the asChild
slot wraps) with .btn plus one .btn-{variant} plus one .btn-{size}
class. Optional icon and trailing slots render before/after children
respectively. Each variant carries a V1 + V2 class alias (e.g. .btn--pri, .btn-primary { … }) so <MatterButton> and <Button> share one CSS recipe.
Variant matrix
| Variant | Use | Background |
|---|---|---|
primary | Default CTA — liquid-glass refractive surface | Painterly white→peach gradient |
outline | Secondary action sitting beside the primary | Translucent white + stone border |
ghost | Tertiary action — navs, inline triggers, dense chrome | Transparent + tone-cascade hover |
dark | High-contrast CTA on warm surfaces (footers, blog hero) | Solid #171717 |
stone | Muted CTA on cool surfaces | Solid --stone-100 |
Size matrix
| Size | Use | Geometry |
|---|---|---|
xs | Toolbar / row-action buttons | Squared, 8px radius |
sm | Dense tables and side rails | Squared, --btn-radius-sm |
md | Default — most product surfaces | Squared, --btn-radius-md |
lg | Display surfaces, hero CTAs in chrome-heavy contexts | Squared, --btn-radius-lg |
sm-pill | Marketing-surface compact CTA | Pill — --radius-pill |
md-pill | Marketing-surface default CTA | Pill — --radius-pill |
lg-pill | Marketing-surface hero CTA | Pill — --radius-pill |
The pill sizes share heights and padding with their squared counterparts — only the border-radius differs.
Polymorphism — asChild vs as
Two polymorphism paths are supported. Prefer asChild (Radix Slot pattern):
<Button asChild variant="dark" size="lg-pill">
<Link href="/get-started">Get started</Link>
</Button>as is kept for back-compat — it accepts an ElementType and renders that
tag directly. When both are set, asChild wins.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | ButtonVariant | "primary" | — |
| size | ButtonSize | "md" | — |
| asChild | boolean | — | Radix Slot pattern — merges .btn classes onto the only child element. |
| as | React.ElementType | — | Legacy ElementType prop; prefer `asChild`. Ignored when asChild is true. |
| icon | React.ReactNode | — | — |
| trailing | React.ReactNode | — | — |
| children | React.ReactNode | — | — |
Also accepts Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children">.
States
Density
Themes
Light / dark / forced-colors side-by-side.
Tokens consumed
Accessibility
- Keyboard interactions
- ARIA roles
- Focus ring uses the canonical peach ring
prefers-reduced-motioncollapses motion to opacity
Do / Don't
Recipes
Where this component shows up in real screens — link to /recipes/* pages.
Source
packages/components/src/ButtonComponents
Every component in @matter/components and @repo/brand — grouped by purpose, click into any card to read its full API, see live previews at every state × theme × density, and copy a working code snippet.
Pill
Small inline tag. Mono-chip-style tones for status / version / ID badges; an announcement-pill shape for marketing surfaces.