# Checkbox

An accessible React checkbox for Next.js forms, with a check that draws itself in and an indeterminate state, built on Radix Checkbox.

Source: https://ui.fewtone.com/components/checkbox

## Installation

```bash
npx shadcn@latest add https://ui.fewtone.com/r/checkbox.json
```

## Usage

```tsx
import { Checkbox } from "@/components/ui/checkbox"

export function Terms() {
  return (
    <>
      <Checkbox id="terms" />
      <label htmlFor="terms">Accept terms and conditions</label>
    </>
  )
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `checked` | `boolean \| "indeterminate"` | – | The state, when you control it. Indeterminate shows a dash. |
| `defaultChecked` | `boolean \| "indeterminate"` | `false` | The initial state. |
| `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | – | Called when the user checks or unchecks it. An indeterminate box becomes checked. |
| `size` | `"sm" \| "md"` | `"md"` | 16 or 20px, the heights of Switch's sizes. |
| `disabled` | `boolean` | `false` | Prevents interaction. |
| `required` | `boolean` | `false` | Must be checked to submit the form. |
| `name` | `string` | – | Submits the value with a form. |
| `value` | `string` | `"on"` | The value submitted when checked. |

**When to use it:** Use Checkbox for choices submitted with a form, agreeing to terms, and picking several items from a list. Set checked to "indeterminate" on a select-all box when only some are picked. Use Switch for settings that apply right away.
**Built on:** Radix Checkbox.
**Accessibility pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/
**npm packages (installed by the CLI):** class-variance-authority@^0.7.1, motion@^14.0.0, radix-ui@^1.7.0.

## Examples

### Default

Check it and the box fills as the check draws itself in; uncheck it and the check erases.

```tsx
import { Checkbox } from "@/components/ui/checkbox";

export default function CheckboxDefault() {
  return <Checkbox aria-label="Accept terms" defaultChecked />;
}
```

### Label and hint

A visible label, and a hint linked with aria-describedby.

```tsx
import { Checkbox } from "@/components/ui/checkbox";
import { useId } from "react";

export default function CheckboxHint() {
  const id = useId();
  return (
    <div className="flex w-full max-w-sm items-start gap-3">
      <Checkbox id={id} aria-describedby={`${id}-hint`} />
      <div className="grid gap-0.5">
        <label htmlFor={id} className="text-sm font-medium">
          Accept terms and conditions
        </label>
        <p id={`${id}-hint`} className="text-sm text-muted-foreground">
          You agree to the Terms of Service and the Privacy Policy.
        </p>
      </div>
    </div>
  );
}
```

### Select all

The parent shows a dash while only some are picked; checking it picks them all. Checked and dash swap marks without the fill moving.

```tsx
"use client";

import { Checkbox } from "@/components/ui/checkbox";
import { useId, useState } from "react";

const channels = [
  { key: "email", label: "Email" },
  { key: "push", label: "Push notifications" },
  { key: "sms", label: "Text messages" },
];

/** The parent is checked when every channel is, a dash when only some are, and empty when none are */
export default function CheckboxSelectAll() {
  const id = useId();
  const [picked, setPicked] = useState<string[]>(["email"]);
  const all = picked.length === channels.length ? true : picked.length > 0 ? "indeterminate" : false;

  return (
    <fieldset className="grid gap-3">
      <legend className="sr-only">Notification channels</legend>
      <div className="flex items-center gap-3">
        <Checkbox
          id={`${id}-all`}
          checked={all}
          onCheckedChange={(checked) =>
            setPicked(checked === true ? channels.map((channel) => channel.key) : [])
          }
        />
        <label htmlFor={`${id}-all`} className="text-sm font-medium">
          All channels
        </label>
      </div>
      {/* Indented to line up with the parent's label: the 20px box plus the 12px gap */}
      <div className="grid gap-3 ps-8">
        {channels.map((channel) => (
          <div key={channel.key} className="flex items-center gap-3">
            <Checkbox
              id={`${id}-${channel.key}`}
              checked={picked.includes(channel.key)}
              onCheckedChange={(checked) =>
                setPicked((current) =>
                  checked === true ? [...current, channel.key] : current.filter((key) => key !== channel.key),
                )
              }
            />
            <label htmlFor={`${id}-${channel.key}`} className="text-sm">
              {channel.label}
            </label>
          </div>
        ))}
      </div>
    </fieldset>
  );
}
```

### Sizes

```tsx
import { Checkbox } from "@/components/ui/checkbox";

export default function CheckboxSizes() {
  return (
    <div className="flex items-center gap-6">
      <Checkbox size="sm" aria-label="Small checkbox" defaultChecked />
      <Checkbox aria-label="Medium checkbox" defaultChecked />
    </div>
  );
}
```

### Disabled

```tsx
import { Checkbox } from "@/components/ui/checkbox";
import { useId } from "react";

export default function CheckboxDisabled() {
  const id = useId();
  return (
    <div className="grid gap-3">
      <div className="flex items-center gap-3">
        <Checkbox id={`${id}-backup`} disabled defaultChecked />
        <label htmlFor={`${id}-backup`} className="text-sm font-medium text-muted-foreground">
          Back up automatically
        </label>
      </div>
      <div className="flex items-center gap-3">
        <Checkbox id={`${id}-mobile`} disabled />
        <label htmlFor={`${id}-mobile`} className="text-sm font-medium text-muted-foreground">
          Sync over mobile data
        </label>
      </div>
    </div>
  );
}
```

## Related

- [Switch](https://ui.fewtone.com/components/switch.md): An accessible React switch for on/off settings, with a spring-animated thumb, built on Radix Switch.
- [Toggle Group](https://ui.fewtone.com/components/toggle-group.md): An accessible React toggle group for Next.js: buttons you switch on and off independently, like Bold, Italic and Underline in a toolbar.
- [Input](https://ui.fewtone.com/components/input.md): An accessible React text input with three sizes and clear invalid, disabled and file states, built on a native input.
