skrewww

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

stableReact AvailableFigma AvailableDocs Partial
React last updated
2026-07-11
Documentation last updated
2026-06-01
Accessibility target
WCAG 2.2 AA (target)
Version
1.0.0

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.
  • UNRESOLVED DESIGN REVIEW: Primary Glass Hover dark content can appear visually muddy over high-frequency/complex backgrounds. Current #17181B content and 24% hover fill match live Figma; any readability adjustment must be approved in Figma first.

Live preview

Interactive Button instances using scoped Skrewww tokens. Shape and surface apply to the examples without changing the documentation shell.

Surface
Shape

Visual variants

Sizes

Small / Medium / Large

States

Default / Disabled / Loading

Icons & layout

Leading icon / Trailing icon / Full width

Icon foreground

Purpose

Primary interactive trigger for user actions — submit, confirm, navigate, initiate a process.

Anatomy

Button = native button or link + visual surface + content row (optional leading/trailing icon + label). Icons are consumer-supplied nodes; Button does not wrap them in SVG or change their paths.

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). React icons inherit Button's CSS color via SVG currentColor — Primary/Danger follow surface-content (light on Flat/Gradient, dark on Glass); Secondary follows primary text. Button does not recolor or rewrite icon artwork.

How do Button icons get their color?

Button sets CSS color only. Primary and Danger use surface-content semantics: inverse/light on Flat and Gradient, dark on Glass. Secondary uses primary text color on every surface. Compatible icons inherit that color through SVG currentColor — Phosphor defaults fill to currentColor; stroke icons should use stroke=currentColor. Button does not set fill, stroke, or icon-specific paint, and it does not rewrite icon artwork. Any compatible icon inherits the same foreground automatically. Icon-only actions use this same Button with an aria-label; there is no separate Icon Button implementation.

Tokens used

component/radius/controlsemantic/action/primarysemantic/action/dangersemantic/surface/defaultsemantic/text/inversesemantic/text/primarysemantic/focus-ringopacity/disabled

Component API

PropTypeDefaultDescription
variant"primary" | "secondary" | "danger""primary"Visual style mapped to semantic action tokens.
size"sm" | "md" | "lg""md"Control height and typography scale.
loadingbooleanfalseDisables interaction, sets aria-busy, and shows a spinner with screen-reader text.
fullWidthbooleanfalseStretches the control to the width of its container.
leadingIconReactNodeOptional icon before the label (Figma: Has Icon + Icon).
trailingIconReactNodeOptional icon after the label. Not confirmed as a Figma Button property.
hrefstringWhen set, renders as a semantic link (Next.js Link or native anchor for external URLs).
targetstringLink target. `_blank` automatically adds `rel="noopener noreferrer"` when rel is omitted.
disabledbooleanfalseNative disabled for buttons; aria-disabled non-navigating link for href variant.
aria-labelstringRequired 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>
  );
}