The primary action component. Severity communicates the intent of the action — proceed, destroy, affirm — while variant controls the visual weight. Reach for Button whenever a user triggers an action; use a Link for navigation instead.
import { Button } from "@idinstudio/ui";Real, interactive examples rendered from the live component.
<Button severity="primary" size="lg">Create project</Button>
<Button variant="outline" severity="danger" iconLeft={<Trash2 />}>Delete</Button>
<Button variant="ghost" loading>Saving…</Button>Every styling and behavioural attribute is a typed prop — no className at the usage site.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "outline" | "ghost" | "soft" | "link" | "default" | Visual treatment. Default is the solid fill; link renders inline with no background. |
severity | "primary" | "secondary" | "danger" | "success" | "warning" | "neutral" | "primary" | Communicates intent. Drives the colour pairing for every variant. |
size | "sm" | "md" | "lg" | "md" | Control height and padding. md is the 44px-min touch target. |
loading | boolean | false | Marks an async action in progress. Suppresses clicks and sets aria-busy. |
disabled | boolean | false | Disables the button and sets aria-disabled. |
fullWidth | boolean | false | Stretches the button to 100% of its container width. |
iconLeft | React.ReactNode | — | Leading icon. Hidden while loading; marked aria-hidden. |
iconRight | React.ReactNode | — | Trailing icon. Marked aria-hidden. |
asChild | boolean | false | Renders children as the root element via Radix Slot — e.g. an anchor. |
type | "button" | "submit" | "reset" | "button" | Native button type. Defaults to button to avoid accidental form submits. |
When to reach for this component, and when not to.
Use a verb-object label — "Create project", "Save changes".
Match severity to intent: danger for destructive, primary for the main path.
Keep one primary button per view so the main action stays obvious.
Set loading during async work so the button reflects progress and blocks double-submits.
Don't use a Button for navigation — use a Link, or asChild with an anchor.
Don't render an icon-only Button — use IconButton, which enforces aria-label.
Don't stack multiple primary buttons side by side; demote the rest to secondary or ghost.
Don't write vague labels like "OK", "Done", or "Click here".
The component's a11y contract. WCAG 2.1 AA is the non-negotiable baseline.
| Key | Action |
|---|---|
| Tab | Move focus onto the button. |
| Shift + Tab | Move focus away from the button. |
| Space | Activate the button. |
| Enter | Activate the button. |