Button
Buttons trigger actions. Use primary for the one main action on a surface, lower-emphasis variants for everything else.
Examples
Variants
Sizes
With icons
Loading
Icon only
Rounded
Disabled
Overview
Button is the primary control for triggering actions. It supports multiple variants for different emphasis levels, three sizes, icons, loading, icon-only, and rounded (pill) shapes. Primary and destructive use a matching border plus a top inset highlight so solid fills read as raised rather than flat.
tsx
import { Button } from "@standard-ui/react" <Button variant="primary" size="md"> Click me </Button>
Usage
Variants
Variants encode emphasis, not taste — pick by the action's role on the surface. The ladder, highest to lowest: primary → secondary / outline → ghost. destructive sits outside the ladder: it encodes danger, not importance.
Always write variant explicitly. The default is primary, so a button without a variant silently becomes a primary CTA.
| Variant | Use it for |
|---|---|
| primary | The single most important action on a surface — modal confirm, form submit, page CTA. At most one per page, panel, modal, or form. |
| secondary | Filled secondary actions on busy surfaces where a border adds noise — cards, dense panels, filter rows. |
| outline | Standalone secondary actions — Cancel next to a primary confirm, header and form side actions. The default when unsure. |
| ghost | Repeated and contextual actions — toolbars, icon buttons, per-row actions, close/dismiss. |
| destructive | Irreversible or dangerous actions only — delete, remove, revoke. Usually the confirm of a confirmation dialog. |
tsx
<Button variant="primary">Save changes</Button> <Button variant="outline">Cancel</Button> <Button variant="secondary">Edit</Button> <Button variant="ghost">More options</Button> <Button variant="destructive">Delete</Button>
Sizes
| Size | Height | Use case |
|---|---|---|
| sm | 32px | Toolbars, inline actions, dense layouts |
| md | 36px | Default — most buttons in the interface |
| lg | 40px | Primary CTAs, hero sections |
tsx
<Button size="sm">Tag</Button> <Button size="md">Submit</Button> <Button size="lg">Get started</Button>
With icons
Prefer prefix / suffix so icons scale with the control. You can still pass icons as children. Mark decorative icons with aria-hidden.
tsx
import { Button, IconPlus } from "@standard-ui/react" <Button variant="primary" prefix={<IconPlus size={16} aria-hidden />}> Add item </Button>
Loading
When loading is true, a spinner replaces the prefix, the button disables, and aria-busy is set. Keep the label so width stays stable.
tsx
<Button loading={isSaving} onClick={handleSave}> Save changes </Button>
Icon only
Use iconOnly for square icon buttons. Always provide an aria-label.
tsx
<Button iconOnly aria-label="Search"> <IconMagnifyingGlass size={16} aria-hidden /> </Button>
Rounded
rounded applies a pill shape. Works with all sizes and variants, including icon-only.
tsx
<Button rounded>Subscribe</Button> <Button rounded iconOnly aria-label="Add"> <IconPlus size={16} aria-hidden /> </Button> <Button rounded variant="ghost" iconOnly aria-label="Add"> <IconPlus size={16} aria-hidden /> </Button>
Disabled
Disabled buttons use reduced opacity and cursor-not-allowed. Prefer explaining why an action is unavailable (helper text or tooltip) instead of a silent disable.
tsx
<Button disabled={!isFormValid}>Submit</Button>API
Button accepts all standard HTML button attributes.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "primary" | "secondary" | "outline" | "ghost" | "destructive" | "primary" | Visual style of the button. |
| size | "sm" | "md" | "lg" | "md" | Size of the button. |
| iconOnly | boolean | false | Square button for icon-only use. |
| rounded | boolean | false | Pill shape (fully rounded corners). |
| prefix | ReactNode | — | Element before the label. |
| suffix | ReactNode | — | Element after the label. |
| loading | boolean | false | Shows a spinner and disables the button. |
| disabled | boolean | false | Disables the button. |
| type | "button" | "submit" | "reset" | "button" | Native button type. |
Guidelines
Do
- Always pass
variantexplicitly — the default isprimary, and an accidental primary is the most common variant bug - Use
primaryfor the main action on a page or in a modal — at most one per surface - Use
outlineorsecondaryfor secondary actions alongside a primary button - Use
ghostfor tertiary, repeated, or contextual actions (toolbars, icon buttons, row actions) - Use
destructiveonly for irreversible or dangerous actions - Pair modal footers as
primary(ordestructive) confirm +outlinecancel - Provide
aria-labelfor icon-only buttons - Use
loadingfor async actions so the control stays focusable and announces busy state - Keep labels concise and action-oriented ("Save", "Delete", "Continue")
Don't
- Don't use multiple
primarybuttons in the same context — there should be one clear primary action - Don't use
destructivefor non-dangerous actions just for visual emphasis - Don't disable buttons without explaining why (consider a tooltip or helper text)
- Don't use icon-only buttons without
aria-label - Don't mix too many button variants in one area — it creates visual noise
- Don't force
cursor-pointeron buttons — reserve the hand cursor for links