# Button

> Buttons let people take an action. Five variants, five colors, three sizes — and an anchor whenever it navigates.

A button is the thing a person clicks to make something happen. `button()` renders a real `<button>` with `type="button"`, so dropping one inside a form does not submit it by accident.

## Basic button

The default is a solid, primary, medium button. Children are the label; anything else is a prop.

```javascript
stack({ direction: 'row', gap: 'md' },
  button('One'),
  button('Two'),
  button('Three'),
)
```

## Variants

Five levels of emphasis, from the one call to action on the page down to something that reads as a link.

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({ variant: 'solid' }, 'Solid'),
  button({ variant: 'soft' }, 'Soft'),
  button({ variant: 'outline' }, 'Outline'),
  button({ variant: 'ghost' }, 'Ghost'),
  button({ variant: 'link' }, 'Link'),
)
```

## Colors

Every themed component draws from the same five palettes, so a `color: 'danger'` button and a `color: 'danger'` alert agree without either of them knowing about the other.

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({ color: 'primary' }, 'Primary'),
  button({ color: 'neutral' }, 'Neutral'),
  button({ color: 'success' }, 'Success'),
  button({ color: 'warning' }, 'Warning'),
  button({ color: 'danger' }, 'Danger'),
)
```

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({ variant: 'soft', color: 'primary' }, 'Primary'),
  button({ variant: 'soft', color: 'neutral' }, 'Neutral'),
  button({ variant: 'soft', color: 'success' }, 'Success'),
  button({ variant: 'soft', color: 'warning' }, 'Warning'),
  button({ variant: 'soft', color: 'danger' }, 'Danger'),
)
```

## Sizes

```javascript
stack({ direction: 'row', gap: 'md', align: 'center', wrap: true },
  button({ size: 'sm' }, 'Small'),
  button({ size: 'md' }, 'Medium'),
  button({ size: 'lg' }, 'Large'),
)
```

## Icons

Pass any SVG markup as `startIcon` or `endIcon`. Icons are sized in `em`, so they scale with the button rather than needing a size of their own.

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({
    startIcon: icon('plus'),
  }, 'New page'),
  button({
    variant: 'outline',
    endIcon: icon('arrow-right'),
  }, 'Continue'),
)
```

## Icon button

`iconButton()` is a square button holding a single icon. Its `label` is required — it becomes the accessible name that the icon itself cannot provide, and the tooltip on hover.

```javascript
stack({ direction: 'row', gap: 'md' },
  iconButton({ label: 'Add', icon: icon('plus') }),
  iconButton({ label: 'Edit', variant: 'soft', icon: icon('edit') }),
  iconButton({ label: 'Delete', variant: 'ghost', color: 'danger', icon: icon('trash') }),
)
```

## Loading and disabled

`loading` swaps in a spinner and sets `aria-busy`, leaving the label in place so the button does not change width mid-action.

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({ loading: true }, 'Saving'),
  button({ variant: 'outline', loading: true }, 'Checking'),
  button({ disabled: true }, 'Disabled'),
  button({ variant: 'soft', disabled: true }, 'Disabled'),
)
```

## Links

Give a button an `href` and it renders an `<a>` instead — the right element for something that navigates. Anchors have no disabled state, so `disabled` becomes `aria-disabled` and removes it from the tab order.

```javascript
stack({ direction: 'row', gap: 'md', wrap: true },
  button({ href: '/docs' }, 'Read the docs'),
  button({ href: '/docs/ui', variant: 'outline' }, 'Components'),
  button({ href: '/docs', variant: 'link' }, 'Plain link'),
)
```

## Full width

```javascript
button({ block: true, size: 'lg' }, 'Deploy site')
```

## Props

Anything not listed here falls through to the rendered element as an attribute — `id`, `data-*`, `onclick`, `commandfor` and the rest.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'solid' \| 'soft' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | How much emphasis the button carries. |
| `color` | `'primary' \| 'neutral' \| 'success' \| 'warning' \| 'danger'` | `'primary'` | Which palette to draw from. |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Height, padding and label size. |
| `href` | `string` | — | Renders an <a> instead of a <button>. |
| `startIcon` | `string` | — | Markup placed before the label. |
| `endIcon` | `string` | — | Markup placed after the label. |
| `loading` | `boolean` | `false` | Shows a spinner and sets aria-busy. |
| `disabled` | `boolean` | `false` | Disables the button, or marks a link aria-disabled. |
| `block` | `boolean` | `false` | Stretches to the full width of its container. |
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Only for the <button> form. |

`iconButton()` takes the same props plus a required `label` and an `icon`.
