Button
Buttons are one of the core building blocks in this UI system. The goal is a small, consistent API that supports common product needs without rewriting styles for every new use case.
This page documents the intended contract (variants, sizes, and behavior). Implementation and examples will be updated as the component library fills out.
When to use a Button
Section titled “When to use a Button”Use a Button for actions:
- submitting or saving
- confirming a decision
- opening a menu or dialog
- navigating when the interaction feels like an action (otherwise use a plain link)
Variants
Section titled “Variants”Variants describe intent. Keep them consistent across the system.
- Default: primary action on a view
- Secondary: supporting action, less emphasis than default
- Outline: neutral action with a visible boundary
- Ghost: subtle action used in dense UI (toolbars, tables)
- Link: action that should look like text, still behaves like a button
- Destructive: irreversible or risky actions
Examples
Section titled “Examples”<Button>Default</Button><Button variant="secondary">Secondary</Button><Button variant="outline">Outline</Button><Button variant="ghost">Ghost</Button><Button variant="link">Link</Button><Button variant="destructive">Delete</Button>Sizes should stay predictable across the system.
- sm: dense UI (tables, toolbars)
- default: most usage
- lg: primary CTA moments (use sparingly)
Examples
<Button size="sm">Small</Button><Button>Default</Button><Button size="lg">Large</Button>States
Section titled “States”Buttons should handle common states consistently, without one-off styling.
At minimum, every Button should support:
- default
- hover
- focus-visible
- active/pressed
- disabled
- loading (recommended when actions can take time)
Disabled
Section titled “Disabled”Disabled buttons should:
- look disabled
- not be clickable
- not show hover/active affordances
If an action is unavailable, prefer explaining why nearby (helper text or inline hint) instead of leaving users guessing.
Loading
Section titled “Loading”If a button triggers async work, loading should:
- preserve the button’s width (avoid layout shift)
- disable repeat clicks
- keep the label readable (or replace with a spinner + accessible text)
Button vs Link
Section titled “Button vs Link”Use a Button when the user triggers an action.
Use a Link when the user navigates somewhere.
If navigation is styled like an action (for example, “View project”), use a Button-style link and keep the behavior as navigation.
Buttons are easy to ship and easy to drift.
This page exists so variants, spacing, and interaction states stay consistent as the component library grows.