No.48 · Buttons· New
Core Button
The everyday button set that product teams ship, done carefully: filled, soft, bordered, bare, destructive, positive, cautionary and text styles, each in three sizes with icons, an icon-only square, a loading state that keeps its width, and a disabled state, on light and dark.
The prompt
Written for the variant you picked above: Primary
Build one reusable button in the style of a modern product design system (crisp, neutral, Inter at 500), in the single style selected below. 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. 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 it at each size, with a leading icon, with a trailing arrow, as an icon-only square, in a 'Save changes' button that loads for 1.6s when pressed, and disabled. Show it on a white panel and a #0a0a0a panel side by side. Selected variant — Primary (primary): Primary: solid ink. Light: #0a0a0a fill, white text, hover #2e2e2e, a faint top highlight (inset 0 1px 0 white at 12%) and a 1px soft shadow. Dark: #ededed fill, #0a0a0a text, hover #cfcfcf. Copy: 'Continue', 'Deploy' with a plus icon. 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 the two panels stack 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 the two panels stack on narrow screens.
- On touch
- Nothing depends on hover; the press scale gives touch feedback.