# Button

A React component in [Beamline](https://beamline.io/)'s [Actions](https://beamline.io/components/actions) category, in the free sample. Live demo: https://beamline.io/components/button

The action control: five weights and a brand fill, a buy/sell tone, sm/md/lg and a 44 px touch size, icon-only, a loading state that keeps its size and focus, and a label that changes in place.

## Use it for

- Any action that happens on click: submit, save, open, run. One primary (or accent) per view.

## Not for

- Navigation to another page (a link; or asChild around the link when it must look like a button).
- A destructive action that needs friction ([confirm-morph](https://beamline.io/components/confirm-morph) or [hold-to-confirm](https://beamline.io/components/hold-to-confirm)).
- Several related actions ([split-button](https://beamline.io/components/split-button) or [dropdown-menu](https://beamline.io/components/dropdown-menu)).

## Anatomy

- root (button, or the child element with asChild)
- leading icon (any icon element among the children, before the text)
- label (the text; its width follows the text when it changes)
- loader (a spinner that opens in front of the label while loading)

## Variants

- **variant**: primary, secondary, outline, ghost, danger, accent
- **size**: sm, md, lg, touch (44 px, bottom action bars on phones)
- **shape**: text (padding on both sides), icon-only (square; detected when there is no text)
- **tone**: up (buy: --pui-up fill or label), down (sell: --pui-down fill or label)

## States

- rest
- hover (arrives at once, leaves over --pui-motion-out)
- pressed (scale 0.97, icon/sm 0.95, at 0ms; none on popup anchors or with reduced motion)
- focus (the look's focus ring, never animated)
- disabled (--pui-opacity-disabled)
- working (loading: loader opens in front of the label, size and focus kept, aria-busy, clicks ignored)
- resolved (the caller changes the label in place, e.g. Save → Saved; never reverted by a timer)
- error (the caller keeps or restores the label and shows the message next to the cause; the button never turns red)

## Keyboard

- Enter / Space activate (native button)
- Tab focuses; focus stays on the button through loading

## Motion

Hover colour arrives at 0ms and leaves over --pui-motion-out. Press scales to 0.97 at once (narrow buttons 0.95) and springs back. A changed label slides up out of a soft blur while the width follows on spring.morph; the loader opens its width from 0 so nothing jumps. Reduced motion: colour changes only, no scale, no slide.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "danger" \| "accent"` | `"primary"` | Visual weight. primary is the ink-filled main action; accent fills with the brand; danger is for destructive actions. |
| `size` | `"sm" \| "md" \| "lg" \| "touch"` | `"md"` | Height 32 / 36 / 40 px; touch 44 px for a bottom action bar on a phone. |
| `tone` | `"up" \| "down"` | — | Market side. On primary/accent the fill becomes --pui-up (buy) or --pui-down (sell) with the matching on-colour ink; on quiet variants the label takes the colour. Pair with a word or arrow. |
| `loading` | `boolean` | — | Shows the loader, sets aria-busy and ignores clicks; size and focus stay. |
| `look` | `"soft" \| "blueprint" \| "glass" \| "metal" \| "glow" \| "pop" \| "mono" \| "ink"` | — | Paint this button in another look than the one in force around it. Primary and accent are solids, secondary a raised control; outline, ghost and danger keep their own quiet paint. |
| `asChild` | `boolean` | — | Render the single child (a link, a Radix trigger) with the button's look and behaviour. |
| `...button attributes` | `ButtonHTMLAttributes` | — | type defaults to "button". Icon-only buttons need aria-label. |

## Dependencies

`motion`, `radix-ui`

## Import

```tsx
import { Button } from "@/components/button/button";
```

## Get it

Button is part of Beamline: 190 React components and screens your coding agent (Claude Code, Codex, Cursor or any MCP client) installs into your app through Beamline's MCP server, as a ready-built package or as plain React source you can change. $49 one payment (regular $200), no subscription, a year of updates, one licence for your whole team. Button is in the free sample, which costs nothing. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in Actions

- [Confirm morph](https://beamline.io/components/confirm-morph): A destructive action that asks in place: the button morphs into its question, then into working, then into the result with Undo or Retry, without a dialog.
- [Copy button](https://beamline.io/components/copy-button): Copies a value and confirms in place: the icon becomes a check and the label says Copied; a refused copy says so instead of pretending.
- [Hold to confirm](https://beamline.io/components/hold-to-confirm): Confirms a costly action by holding instead of clicking: a fill sweeps across while held and drains if let go early; pointer, touch, Space and Enter all…
- [Split button](https://beamline.io/components/split-button): One obvious action joined to a menu of close alternatives; both halves are real buttons and the menu uses the shared menu rows.
- [Swipe actions](https://beamline.io/components/swipe-actions): Row actions behind a swipe on touch screens, mirrored in a menu at the row's end for pointer and keyboard; a full swipe runs the edge action.
- [Theme switch](https://beamline.io/components/theme-switch): The light/dark control: the page changes in one of four transitions starting from the button (reveal, eclipse, split, rise), and the icon turns between…
