Button
An action component with intent and appearance axes. Communicates what an action does, not just what it looks like.
Button applies the same semantic axes as Badge: intent says what kind of action this is, appearance says how much attention it should demand. You never pick a color — you pick a meaning.
Intent × Appearance
solid is the default for primary actions. soft for secondary. ghost for low-emphasis actions in tight contexts. outline when you need a visible border without a fill.
Destructive pattern
A confirmation dialog is the clearest example of why intent matters. The buttons say what will happen — not what color they are.
<Button intent="neutral" appearance="outline">Cancel</Button>
<Button intent="danger">Delete account</Button>Size
<Button size="sm">Small</Button>
<Button size="md">Medium</Button> {/* default */}
<Button size="lg">Large</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
intent | "neutral" | "brand" | "danger" | "success" | "neutral" | What kind of action this is. Drives color and emphasis. |
appearance | "solid" | "soft" | "ghost" | "outline" | "solid" | How much visual weight the button should carry. |
size | "sm" | "md" | "lg" | "md" | Size variant. |
className | string | — | Layout overrides only (margin, width). |
disabled | boolean | — | Disables interaction and reduces opacity. |
All standard <button> attributes (onClick, type, aria-label, etc.) are forwarded.
Design rules
No color via className. If you need a green button, the answer is intent="success", not className="bg-green-600".
intent="danger" for destructive actions. Any action that deletes, removes, or cannot easily be undone should use intent="danger". This is a system-level semantic, not a stylistic preference.
Reserve solid for primary actions. In a section with one primary action, it should be solid. Secondary actions should be soft, ghost, or outline.
Source
packages/ui/src/button.tsx — copy into components/ui/button.tsx in your project.