Actions
Button
Button is a primary interactive trigger for user actions — submit, confirm, navigate, or initiate a process.
Style (Primary/Secondary/Danger) × Size (Small/Medium/Large) × State (Default/Hover/Pressed/Focused/Disabled) — 45 variants
betaReact AvailableFigma AvailableDocs Partial
- React last updated
- 2026-07-11
- Documentation last updated
- 2026-06-01
- Accessibility target
- WCAG 2.2 AA (target)
- Version
- 0.1.0-beta
Known open questions
- Confirm exact control height and horizontal padding per size from Figma.
- Trailing icon is not defined as a separate Figma property on Button — supported in code for composition; confirm with design.
- Gradient and Glass surface personalities for Button need Surface collection token values.
Live preview
Interactive Button instances using Skrewww tokens. Shape and surface are controlled globally through CSS custom properties — not separate component files.
Visual variants
Sizes
Small / Medium / Large
States
Default / Disabled / Loading
Icons & layout
Leading icon / Trailing icon / Full width
Purpose
Primary interactive trigger for user actions — submit, confirm, navigate, initiate a process.
Variants and states
primary · secondary · danger
When to use
For the main action(s) in a view. Use Primary for the single most important action, Secondary for alternative/less prominent actions, Danger for destructive actions requiring confirmation.
When not to use
For page-to-page navigation (use Link). For toggling a binary state (use Switch). For a single icon-only action (use Icon Button).
Accessibility
Renders as a real <button>, not a styled <div>. Keyboard: Tab to focus, Enter/Space to activate. Focus uses semantic/focus-ring (5.31:1 contrast, confirmed on the Accessibility page). Never rely on the Disabled state alone to explain unavailability — pair with visible explanatory text nearby.
Common mistakes
More than one Primary button in the same view (dilutes hierarchy). Not disabling the button during an async action (allows double-submission). Skipping a confirmation step for Danger actions just because the button is red.
Properties
Style × Size × State as variants. Label (text). Has Icon (boolean) + Icon (instance-swap).
Tokens used
component/radius/controlsemantic/action/primarysemantic/action/dangersemantic/surface/defaultsemantic/text/inversesemantic/text/primarysemantic/focus-ringopacity/disabled
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "primary" | "secondary" | "danger" | "primary" | Visual style mapped to semantic action tokens. |
| size | "sm" | "md" | "lg" | "md" | Control height and typography scale. |
| loading | boolean | false | Disables interaction, sets aria-busy, and shows a spinner with screen-reader text. |
| fullWidth | boolean | false | Stretches the control to the width of its container. |
| leadingIcon | ReactNode | — | Optional icon before the label (Figma: Has Icon + Icon). |
| trailingIcon | ReactNode | — | Optional icon after the label. Not confirmed as a Figma Button property. |
| href | string | — | When set, renders as a semantic link (Next.js Link or native anchor for external URLs). |
| target | string | — | Link target. `_blank` automatically adds `rel="noopener noreferrer"` when rel is omitted. |
| disabled | boolean | false | Native disabled for buttons; aria-disabled non-navigating link for href variant. |
| aria-label | string | — | Required accessible name for icon-only buttons. |
React example
Copy React example
import { Plus } from "@phosphor-icons/react";
import { Button } from "@/components/ui/Button";
export function Example() {
return (
<Button variant="primary" leadingIcon={<Plus size={16} />} type="button">
Create project
</Button>
);
}