Button
One button, two axes: variant sets the visual weight (how much attention it demands) and tone sets the meaning (brand, neutral, success, danger). Every pairing works — no more one-off variants for every color.
Variants — visual weight
From strongest to quietest. A view usually wants exactly one solid button; support it with outline, soft or ghost neighbors.
Snippet
import { Button } from '@creo-team/buzz-ui/client'
<Button>Solid</Button> {/* the default */}
<Button variant="soft">Soft</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="glass">Glass</Button>Tones — meaning
Tones re-color any weight. Omitted, solid and link default to primary while the quieter weights default to neutral — chrome stays chrome unless you say otherwise.
| tone ↓ | solid | soft | outline | ghost | link |
|---|---|---|---|---|---|
| primary | |||||
| neutral | |||||
| success | |||||
| danger |
Snippet
<Button tone="danger">Delete</Button> {/* solid danger */}
<Button variant="soft" tone="success">Approve</Button>
<Button variant="outline" tone="danger">Remove</Button>
<Button variant="ghost" tone="primary">Learn more</Button>
<Button tone="neutral">High contrast</Button> {/* inverse button */}Sizes
Snippet
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>States
Snippet
<Button disabled>Disabled</Button>
<Button loading>Loading</Button>
<Button fullWidth>Full Width</Button>With icons
Icon-only buttons
Snippet
<Button>
<PlusIcon className="h-4 w-4" />
Add Item
</Button>
{/* Icon-only: circular hit area; always label it for screen readers */}
<Button variant="ghost" iconOnly aria-label="Settings">
<GearIcon className="h-5 w-5" />
</Button>Selected state
Snippet
{/* selected sets aria-pressed — use it for toggles */}
<Button variant="ghost" selected={view === 'grid'} onClick={() => setView('grid')}>
Grid
</Button>Toggle button group
Snippet
function ToggleButtonGroup() {
const [selected, setSelected] = useState('grid')
return (
<div className="inline-flex gap-0.5 rounded-xl border border-[var(--c-border)] p-0.5">
{options.map(option => (
<Button
key={option.value}
variant="ghost"
size="sm"
selected={selected === option.value}
onClick={() => setSelected(option.value)}
>
{option.icon}
{option.label}
</Button>
))}
</div>
)
}Migrating from v0.6
The ten flat v0.6 variants keep working as deprecated aliases — no breakage — but new code should use the axes:
| v0.6 | now |
|---|---|
variant="bold" | (default — just <Button>) |
variant="success" | tone="success" |
variant="danger" | tone="danger" |
variant="subtle" | variant="soft" |
variant="text" | variant="link" |
variant="nav" | variant="ghost" |
variant="icon" | variant="ghost" iconOnly |
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'glass' | 'solid' | Visual weight. v0.6 names are accepted as deprecated aliases. |
tone | 'primary' | 'neutral' | 'success' | 'danger' | 'primary' (solid/link), 'neutral' otherwise | Semantic color, orthogonal to variant. |
size | 'sm' | 'md' | 'lg' | 'md' | Size preset for padding and text. |
loading | boolean | false | Shows a spinner, disables interaction, sets aria-busy. |
selected | boolean | — | Toggle state — sets aria-pressed and the selected styling. |
hotkey | string | { key, description?, action? } | — | Keyboard shortcut that clicks the button (e.g. 'mod+s'). |
iconOnly | boolean | false | Circular icon button — pair with aria-label. |
fullWidth | boolean | false | Stretch to the container's width. |
asChild | boolean | false | Render the child element (e.g. a framework Link) with button styling. |
...props | React.ButtonHTMLAttributes<HTMLButtonElement> | — | All standard button attributes. |
See the full API: /components/button/api