Skip to content

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: primarysecondary / outlineghost. 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.

VariantUse it for
primaryThe single most important action on a surface — modal confirm, form submit, page CTA. At most one per page, panel, modal, or form.
secondaryFilled secondary actions on busy surfaces where a border adds noise — cards, dense panels, filter rows.
outlineStandalone secondary actions — Cancel next to a primary confirm, header and form side actions. The default when unsure.
ghostRepeated and contextual actions — toolbars, icon buttons, per-row actions, close/dismiss.
destructiveIrreversible 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

SizeHeightUse case
sm32pxToolbars, inline actions, dense layouts
md36pxDefault — most buttons in the interface
lg40pxPrimary 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.

PropTypeDefaultDescription
variant"primary" | "secondary" | "outline" | "ghost" | "destructive""primary"Visual style of the button.
size"sm" | "md" | "lg""md"Size of the button.
iconOnlybooleanfalseSquare button for icon-only use.
roundedbooleanfalsePill shape (fully rounded corners).
prefixReactNodeElement before the label.
suffixReactNodeElement after the label.
loadingbooleanfalseShows a spinner and disables the button.
disabledbooleanfalseDisables the button.
type"button" | "submit" | "reset""button"Native button type.

Guidelines

Do

  • Always pass variant explicitly — the default is primary, and an accidental primary is the most common variant bug
  • Use primary for the main action on a page or in a modal — at most one per surface
  • Use outline or secondary for secondary actions alongside a primary button
  • Use ghost for tertiary, repeated, or contextual actions (toolbars, icon buttons, row actions)
  • Use destructive only for irreversible or dangerous actions
  • Pair modal footers as primary (or destructive) confirm + outline cancel
  • Provide aria-label for icon-only buttons
  • Use loading for 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 primary buttons in the same context — there should be one clear primary action
  • Don't use destructive for 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-pointer on buttons — reserve the hand cursor for links