Default
Show the codeHide the code
Default, code
<Button>Save changes</Button>Triggers an action. Text label always; use IconButton for icon-only actions.
These are the real React components. Use them with a mouse, touch or keyboard, and switch the theme and density for every example at once.
Default, code
<Button>Save changes</Button>Variants, code
<div className="flex flex-wrap items-center gap-gap-md">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete project</Button>
<Button variant="link">Read the guide</Button>
</div>Sizes, code
<div className="flex flex-wrap items-center gap-gap-md">
<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
</div>With icons, code
<div className="flex flex-wrap items-center gap-gap-md">
<Button iconStart={Plus}>New project</Button>
<Button variant="outline" iconEnd={ArrowRight}>Continue</Button>
<Button variant="destructive" iconStart={Trash2}>Remove member</Button>
</div>Loading, code
<Button isLoading>Saving</Button>Disabled, code
<div className="flex flex-wrap items-center gap-gap-md">
<Button isDisabled>Default</Button>
<Button variant="secondary" isDisabled>Secondary</Button>
<Button variant="outline" isDisabled>Outline</Button>
<Button variant="ghost" isDisabled>Ghost</Button>
<Button variant="destructive" isDisabled>Destructive</Button>
</div>The 36 design tokens Button reads, with the value each has in the theme and density chosen above. Change a token and the component follows, in Figma and in code.
| Token | Value now | CSS variable |
|---|---|---|
| button.danger.bg | … | --sd-button-danger-bg |
| button.danger.bg-hover | … | --sd-button-danger-bg-hover |
| button.danger.bg-pressed | … | --sd-button-danger-bg-pressed |
| button.danger.fg | … | --sd-button-danger-fg |
| button.disabled.bg | … | --sd-button-disabled-bg |
| button.disabled.border | … | --sd-button-disabled-border |
| button.disabled.fg | … | --sd-button-disabled-fg |
| button.gap | … | --sd-button-gap |
| button.ghost.bg-hover | … | --sd-button-ghost-bg-hover |
| button.ghost.bg-pressed | … | --sd-button-ghost-bg-pressed |
| button.ghost.fg | … | --sd-button-ghost-fg |
| button.height.lg | … | --sd-button-height-lg |
| button.height.md | … | --sd-button-height-md |
| button.height.sm | … | --sd-button-height-sm |
| button.hit-area | … | --sd-button-hit-area |
| button.link.fg | … | --sd-button-link-fg |
| button.link.fg-pressed | … | --sd-button-link-fg-pressed |
| button.outline.bg | … | --sd-button-outline-bg |
| button.outline.bg-hover | … | --sd-button-outline-bg-hover |
| button.outline.bg-pressed | … | --sd-button-outline-bg-pressed |
| button.outline.border | … | --sd-button-outline-border |
| button.outline.fg | … | --sd-button-outline-fg |
| button.padding-x.lg | … | --sd-button-padding-x-lg |
| button.padding-x.md | … | --sd-button-padding-x-md |
| button.padding-x.sm | … | --sd-button-padding-x-sm |
| button.primary.bg | … | --sd-button-primary-bg |
| button.primary.bg-hover | … | --sd-button-primary-bg-hover |
| button.primary.bg-pressed | … | --sd-button-primary-bg-pressed |
| button.primary.fg | … | --sd-button-primary-fg |
| button.secondary.bg | … | --sd-button-secondary-bg |
| button.secondary.bg-hover | … | --sd-button-secondary-bg-hover |
| button.secondary.bg-pressed | … | --sd-button-secondary-bg-pressed |
| button.secondary.fg | … | --sd-button-secondary-fg |
| motion.duration.fast | … | --sd-motion-duration-fast |
| motion.easing.standard | … | --sd-motion-easing-standard |
| shape.radius-control | … | --sd-shape-radius-control |
The npm package isn’t published yet. When it is, this is the install line; until then, this page runs the same build of the package (from commit fa3abf8).
Install
npm i @superduperui/react @superduperui/tokensImport
import { Button, buttonVariants } from "@superduperui/react"Button also takes the props of the React Aria component it’s built on.
| Prop | Type | What it does |
|---|---|---|
variant | 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link' | shadcn meanings: default = primary (one per view); secondary = filled brand tint, no border; outline = bordered on the canvas; ghost = no fill until hovered; destructive = danger fill; link = underlined text action. Figma's Variant options are the same six in Title Case. |
size | 'sm' | 'default' | 'lg' | sm 36px visual (44px hit area), default 44px, lg 52px. |
childrenrequired | ReactNode | The visible label. Always text: never an icon alone (use IconButton). |
iconStart | LucideIcon | Lucide icon before the label (decorative). |
iconEnd | LucideIcon | Lucide icon after the label (decorative). |
isLoading | boolean | Pending state: keeps the label, shows a spinner, sets aria-busy and blocks presses while staying focusable. |
Screen readers announce "Save changes, button"; loading adds "busy".
WCAG 2.2 AAA criteria the component meets in Comfortable density: 1.4.6, 1.4.9, 2.1.3, 2.3.2, 2.4.13, 2.5.5, 2.5.6, 2.3.3.
Compact density meets AA (2.5.8, 24px targets), not AAA.
Shared patterns it ships with: 3.3.6 (destructive actions pair with an alert dialog or undo).
| axe-core (WCAG A, AA, AAA and best practice) | 160 runs across every story, theme, density and width: 0 violations |
|---|---|
| Rendered text contrast | 260 text runs: 0 below 7:1, lowest 7.79:1 |
| Target size | 90 targets: 0 under 44px in Comfortable |
| Focus appearance (2.4.13) | 126 focus stops in 3 browser engines: all pass |
| Keyboard script | Chromium 3 of 3, Firefox 3 of 3, WebKit 3 of 3 |
Manual passes with VoiceOver and NVDA haven’t been done yet.
Each step is scripted and run in Chromium, Firefox and WebKit.
| Key | What happens |
|---|---|
| Tab | Tab reaches the button |
| Enter | Enter activates |
| Space | Space activates |
The Figma component is Button, with Variant (Default, Secondary, Outline, Ghost, Destructive, Link); Size (Small, Default, Large); State (Default, Hover, Pressed, Focus, Disabled, Loading). The Figma library isn’t published yet.
Figma to code: Variant → variant (Default = "default", Secondary = "secondary", Outline = "outline", Ghost = "ghost", Destructive = "destructive", Link = "link"); Size → size (Small = "sm", Default = "default", Large = "lg"); State (Default, Hover, Pressed, Focus, Disabled = isDisabled, Loading = isLoading); Label → children; Leading icon → iconStart when Show leading icon; Trailing icon → iconEnd when Show trailing icon.