Skip to content

No.49 · Buttons· New

Button Set

The everyday button set that product teams ship, done carefully: primary, secondary, outline, ghost, danger, success, warning and link styles, each in three sizes with icons, an icon-only square, a loading state that keeps its width, and a disabled state.

The prompt

Copy this text

Automatic copying is unavailable. Copy the selected text using your device’s copy command.

Written for the variant you picked above: Light

Build one reusable button in the style of a modern product design system (crisp, neutral, Inter at 500), with eight styles: primary, secondary, outline, ghost, danger, success, warning and link. Anatomy: a native <button type="button"> laid out as an inline flex row with an 8px gap. Sizes: small 32px tall, 12px side padding, 6px radius, 13.5px text, 14px icons; medium 40px, 16px, 8px radius, 15px text, 16px icons; large 48px, 22px, 10px radius, 16px text, 18px icons. Letter-spacing -0.01em, no wrapping. Optional icon before the label and optional icon after it (the trailing one slides 2px right on hover). With only an icon and an aria-label it becomes a square. Styles (light / dark): primary is solid ink (#0a0a0a with white text, hover #2e2e2e / #ededed with #0a0a0a text, hover #cfcfcf) with a faint top highlight (inset 0 1px 0 white at 12%) and a 1px soft shadow; secondary is a soft neutral fill with no shadow (#f2f2f2, hover #e6e6e6 / #1f1f1f, hover #2b2b2b); outline is transparent with a 1px inset ring (#d9d9d9, #a8a8a8 on hover / #343434, #5c5c5c) and a 5% wash on hover (7% white on dark); ghost has no fill or ring until a hover wash; danger is red #dc2626 (hover #b91c1c / #e5484d, hover #f2555a) with white text; success is green #15803d (hover #166534 / #238636, hover #2a9a40) with white text; warning is amber #f5a524 with dark brown #241700 text (hover #e3920b / #ffb53d); link is text only in #2563eb / #6ea8fe with a 1.5px underline (offset 4px) that fades in on hover and a 75% dim on press. States: hover changes the fill over 0.15s; press scales to 0.97; keyboard focus shows a 2px #2563eb ring 2px outside (#6ea8fe on dark). Loading: the content fades to opacity 0 but keeps its space (so neither the width nor the accessible name changes), a 16px spinner (2px border with one side clear, 0.7s per turn) sits in the middle, and the button gets aria-busy and aria-disabled and ignores clicks. Disabled: native disabled, 45% opacity, a not-allowed cursor, no hover. Show a sheet with one row per style, each row showing the three sizes, a leading icon, a trailing arrow, an icon-only square (not for link), a 'Save' button that loads for 1.6s when pressed, and a disabled one, on a white or #0a0a0a page. Selected variant — Light (light): Palette for this theme (Light): --cbtn-danger #dc2626; --cbtn-danger-hover #b91c1c; --cbtn-edge #d9d9d9; --cbtn-edge-hover #a8a8a8; --cbtn-focus #2563eb; --cbtn-hover-wash rgb(0 0 0 / 0.05); --cbtn-ink #0a0a0a; --cbtn-link #2563eb; --cbtn-paper #ffffff; --cbtn-soft #f2f2f2; --cbtn-soft-hover #e6e6e6; --cbtn-solid-hover #2e2e2e; --cbtn-success #15803d; --cbtn-success-hover #166534; --cbtn-warning #f5a524; --cbtn-warning-hover #e3920b. Treat these as the root colour tokens, one value per role, and name them to suit your code. Select it with the theme option set to "light". Keep every dimension, spacing value, state and motion from the brief unchanged, and keep text at 4.5:1 contrast or better on these surfaces. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: A real button: Enter and Space press it; loading buttons ignore presses; disabled buttons are skipped by Tab. Motion: 0.15s fill and ring changes, a 0.97 press, a 2px slide of the trailing icon and a 0.7s spinner. Reduced motion removes the press and slide and slows the spinner. Accessibility: Native button semantics. Loading keeps the label in the accessibility tree and sets aria-busy and aria-disabled; icon-only buttons need an aria-label; every fill keeps its text at 4.5:1 or better. Responsive behavior: Buttons keep their size; rows wrap, and each style's label moves above its buttons on narrow screens. Touch: Nothing depends on hover; the press scale gives touch feedback. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.

Notes

Interaction
A real button: Enter and Space press it; loading buttons ignore presses; disabled buttons are skipped by Tab.
Motion
0.15s fill and ring changes, a 0.97 press, a 2px slide of the trailing icon and a 0.7s spinner. Reduced motion removes the press and slide and slows the spinner.
Accessibility
Native button semantics. Loading keeps the label in the accessibility tree and sets aria-busy and aria-disabled; icon-only buttons need an aria-label; every fill keeps its text at 4.5:1 or better.
Responsive
Buttons keep their size; rows wrap, and each style's label moves above its buttons on narrow screens.
On touch
Nothing depends on hover; the press scale gives touch feedback.

Featured

425 components