# Checkbox

> A checkbox and its label as one control — a real input, styled with CSS rather than replaced.

`checkbox()` renders a `<label>` wrapping a real `<input type="checkbox">` and the box you see. The input is visually hidden but still there, so it is focusable, it submits, and the whole label is a hit target — the tick mark is drawn from the input’s own `:checked` state, with no script involved.

## Basic checkbox

```javascript
stack({ direction: 'row', gap: 'lg' },
  checkbox({ label: 'Email me updates', name: 'updates' }),
  checkbox({ label: 'Checked', name: 'checked', checked: true }),
)
```

## Colors

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

## Disabled

```javascript
stack({ direction: 'row', gap: 'lg' },
  checkbox({ label: 'Unavailable', disabled: true }),
  checkbox({ label: 'On, and locked', checked: true, disabled: true }),
)
```

## Long labels

The box stays aligned with the first line rather than centring itself against a paragraph.

```javascript
checkbox({
  label: 'Run a Lighthouse audit after every build, and fail the build when a score drops below its threshold.',
  name: 'lighthouse',
  checked: true,
})
```

## Groups

`choiceGroup()` builds a set of checkboxes from data, with a shared legend and name. Pass an array as `value` to tick several.

```javascript
choiceGroup({
  legend: 'Generate',
  name: 'generate',
  type: 'checkbox',
  value: ['sitemap', 'rss'],
  options: [
    { value: 'sitemap', label: 'sitemap.xml' },
    { value: 'rss', label: 'rss.xml' },
    { value: 'pagefind', label: 'Pagefind index' },
  ],
  help: 'Each one is written into dist/ at the end of the build.',
})
```

## In a row

```javascript
choiceGroup({
  legend: 'Categories',
  name: 'categories',
  type: 'checkbox',
  direction: 'row',
  value: ['performance'],
  options: ['performance', 'accessibility', 'seo'],
})
```

## With a field

A single checkbox rarely needs a label above it as well. When a group does, `field()` gives it the same label, help and error treatment as a text field.

```javascript
field({ label: 'Terms', error: 'You need to accept the terms to continue.' },
  checkbox({ label: 'I accept the terms', name: 'terms', color: 'danger' }),
)
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `Child` | — | Text beside the box. Omit it for a bare control. |
| `color` | `'primary' \| 'neutral' \| 'success' \| 'warning' \| 'danger'` | `'primary'` | Colour when checked. |
| `checked` | `boolean` | `false` | Whether it starts ticked. |
| `name` | `string` | — | Form field name. |
| `value` | `string \| number` | — | Value submitted when checked. |
| `disabled` | `boolean` | `false` | Disables the input and dims the label. |

Anything else lands on the `<input>`, not the label — so `required`, `onchange` and `data-*` go where you would expect. Use `class` to style the label itself.

For a set built from data, see `choiceGroup()` on the `Radio group` page — it takes the same options either way, switched by `type: 'checkbox'`.
