---
id: "packages/active-ui/checkbox"
title: "Checkbox"
description: "A box the reader checks or clears, for a yes or no in a form and for several choices from a list, with an indeterminate state."
url: "/packages/active-ui/checkbox"
locale: "en"
revision: "6c25278cbe9f3772"
---

# Checkbox

A checkbox is a form control for a yes or no that is submitted later: accepting conditions,
choosing the channels of a statement. For a setting that takes effect at once, use a
[switch](/packages/active-ui/switch); for one choice out of several, a
[radio group](/packages/active-ui/radio-group).

**Example: Select all, a choice card, disabled and invalid**

Client: Runs entirely in your browser. Source: `examples/ui/checkbox.tsx`.

```tsx
// apps/docs/examples/ui/checkbox.tsx
'use client';

import {useState} from 'react';

import {Checkbox} from '@workspace/active-ui/components/primitives/checkbox';
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldGroup,
  FieldLabel,
  FieldLegend,
  FieldSet,
  FieldTitle,
} from '@workspace/active-ui/components/primitives/field';

const CHANNELS = [
  {id: 'email', label: 'Email'},
  {id: 'letter', label: 'Letter'},
  {id: 'portal', label: 'Portal message'},
];

/**
 * Checkboxes beside their label, as a choice card with a description, and a
 * "select all" box that is indeterminate while only some are checked. Each
 * box is a `Checkbox` in a horizontal `Field`, labelled by a `FieldLabel`.
 */
export default function CheckboxExample() {
  const [channels, setChannels] = useState<string[]>(['email']);
  const all = channels.length === CHANNELS.length;
  const some = channels.length > 0 && !all;
  return (
    <div className="grid w-full max-w-sm gap-8">
      <FieldSet>
        <FieldLegend variant="label">Send statements by</FieldLegend>
        <FieldGroup className="gap-3">
          <Field orientation="horizontal">
            <Checkbox
              id="channel-all"
              checked={all}
              indeterminate={some}
              onCheckedChange={(checked) =>
                setChannels(checked ? CHANNELS.map((c) => c.id) : [])
              }
            />
            <FieldLabel htmlFor="channel-all">Every channel</FieldLabel>
          </Field>
          {CHANNELS.map((channel) => (
            <Field key={channel.id} orientation="horizontal" className="ps-6">
              <Checkbox
                id={`channel-${channel.id}`}
                checked={channels.includes(channel.id)}
                onCheckedChange={(checked) =>
                  setChannels((current) =>
                    checked
                      ? [...current, channel.id]
                      : current.filter((id) => id !== channel.id),
                  )
                }
              />
              <FieldLabel htmlFor={`channel-${channel.id}`}>
                {channel.label}
              </FieldLabel>
            </Field>
          ))}
        </FieldGroup>
      </FieldSet>

      <FieldLabel htmlFor="reminder">
        <Field orientation="horizontal">
          <Checkbox id="reminder" defaultChecked />
          <FieldContent>
            <FieldTitle>Payment reminder</FieldTitle>
            <FieldDescription>
              Sent five days before a contribution is due.
            </FieldDescription>
          </FieldContent>
        </Field>
      </FieldLabel>

      <div className="grid gap-3">
        <Field orientation="horizontal" data-disabled>
          <Checkbox id="paper" disabled />
          <FieldLabel htmlFor="paper">Paper copy (not offered)</FieldLabel>
        </Field>
        <Field orientation="horizontal" data-invalid>
          <Checkbox id="terms" aria-invalid />
          <FieldLabel htmlFor="terms">I have read the conditions</FieldLabel>
        </Field>
      </div>
    </div>
  );
}
```

## Usage

```tsx
import {Checkbox} from '@workspace/active-ui/components/primitives/checkbox';
import {
  Field,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';

<Field orientation="horizontal">
  <Checkbox id="terms" />
  <FieldLabel htmlFor="terms">I have read the conditions</FieldLabel>
</Field>;
```

## States

- **Checked:** `checked` and `onCheckedChange` (controlled) or `defaultChecked`.
- **Indeterminate:** `indeterminate` shows a dash instead of a check, for a box that stands for a
  list of which only some are checked. It is a display state: the box reports
  `aria-checked="mixed"`, and a click checks it. Your application decides what checking it means,
  as the "Every channel" box in the example does.
- **Disabled:** `disabled` skips the box with the keyboard and dims it; `data-disabled` on the
  `Field` dims the label.
- **Invalid:** `aria-invalid` gives the box the error border.

## Choice cards

Put a `Field` with a checkbox and a `FieldContent` inside a `FieldLabel`: the whole card becomes
the label. A click anywhere on it toggles the box, the card tints while checked, and keyboard focus
on the box outlines the card. See [Field](/packages/active-ui/field) for the parts.

## In a form

The checkbox renders a hidden `<input type="checkbox">` beside its button, so it takes part in a
native form: give it a `name` and, if the submitted value is not `on`, a `value`. Base UI's
`Field` and `Form` can validate it; the package's `Field` only lays it out.

## What your application provides

- A label for every box, usually a `FieldLabel` with `htmlFor`.
- The state of a "select all" box, and the list it stands for.
- The validation message when a box is required.

## Accessibility and keyboard

- `Space` toggles the focused box; `Tab` moves between boxes.
- The box is a `role="checkbox"` button with `aria-checked` (`true`, `false` or `mixed`).
- The hit area extends a few pixels beyond the visible box, so it is easier to tap.

## API

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `checked` | `boolean` | no | Whether the checkbox is currently ticked.  To render an uncontrolled checkbox, use the `defaultChecked` prop instead. |
| `defaultChecked` | `boolean` | no | Whether the checkbox is initially ticked.  To render a controlled checkbox, use the `checked` prop instead. |
| `disabled` | `boolean` | no | Whether the component should ignore user interaction. |
| `form` | `string` | no | Identifies the form that owns the hidden input. Useful when the checkbox is rendered outside the form. |
| `id` | `string` | no | The id of the input element. |
| `indeterminate` | `boolean` | no | Whether the checkbox is in a mixed state: neither ticked, nor unticked. |
| `inputRef` | `Ref<HTMLInputElement>` | no | A ref to access the hidden `<input>` element. |
| `name` | `string` | no | Identifies the field when a form is submitted. |
| `nativeButton` | `boolean` | no | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `true` if the rendered element is a native button. |
| `onCheckedChange` | `((checked: boolean, eventDetails: CheckboxRootChangeEventDetails) => void)` | no | Event handler called when the checkbox is ticked or unticked. |
| `parent` | `boolean` | no | Whether the checkbox controls a group of child checkboxes.  Must be used in a [Checkbox Group](https://base-ui.com/react/components/checkbox-group). |
| `readOnly` | `boolean` | no | Whether the user should be unable to tick or untick the checkbox. |
| `render` | `ComponentRenderFn<HTMLProps, CheckboxRootState> \| ReactElement<unknown, string \| JSXElementConstructor<any>>` | no | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| `required` | `boolean` | no | Whether the user must tick the checkbox before submitting a form. |
| `uncheckedValue` | `string` | no | The value submitted with the form when the checkbox is unchecked. By default, unchecked checkboxes do not submit any value, matching native checkbox behavior. |
| `value` | `string` | no | The checkbox's value. Identifies it within a [Checkbox Group](https://base-ui.com/react/components/checkbox-group), falling back to `name` when omitted. When submitting a form, a checked box submits `value`; with no `value`, it submits the native "on". |

> [!NOTE]
> **Based on shadcn/ui**
>
> This page adapts the Checkbox documentation of shadcn/ui (MIT licence) to this
> package; see [Third-party notices](/third-party-notices).
