# Checkbox (/ui/components/react/checkbox)



<Playground component="checkbox" />

## Usage [#usage]

```tsx
import { Checkbox } from '@appica/ui-react/checkbox'
```

```tsx
<label className="flex items-center gap-2">
  <Checkbox defaultChecked />
  Accept terms and conditions
</label>
```

`Checkbox` renders only the box — it has no text of its own. Wrap it and its label in a single `<label>` so clicking either toggles the box and assistive tech announces them together; no `id`/`htmlFor` wiring needed. Use it uncontrolled with `defaultChecked`, or controlled with `checked` + `onCheckedChange`. The animated check and squish are skipped when the user prefers reduced motion.

To manage several related checkboxes as one value, reach for [`CheckboxGroup`](#checkboxgroup).

## Examples [#examples]

### States [#states]

A checkbox is `unchecked`, `checked`, or `indeterminate` (a mixed state, drawn as a dash). Any of them can also be `disabled`.

```tsx
import { Checkbox } from '@appica/ui-react/checkbox'

export default function CheckboxStates() {
  return (
    <div className="flex flex-wrap items-center gap-6 text-sm select-none">
      <label className="flex items-center gap-2">
        <Checkbox />
        Unchecked
      </label>
      <label className="flex items-center gap-2">
        <Checkbox defaultChecked />
        Checked
      </label>
      <label className="flex items-center gap-2">
        <Checkbox indeterminate />
        Indeterminate
      </label>
      <label className="text-foreground-muted flex items-center gap-2">
        <Checkbox disabled />
        Disabled
      </label>
      <label className="text-foreground-muted flex items-center gap-2">
        <Checkbox disabled defaultChecked />
        Disabled checked
      </label>
      <label className="flex items-center gap-2">
        <Checkbox aria-invalid />
        Error
      </label>
    </div>
  )
}
```

### Sizing [#sizing]

`Checkbox` is sized in `em`, so it scales with the surrounding font size — set a `text-*` class on the wrapping `<label>` and the box and text grow together. It won't shrink below a 16px floor.

```tsx
import { Checkbox } from '@appica/ui-react/checkbox'

export default function CheckboxSizing() {
  return (
    <div className="flex flex-col items-start gap-4 select-none">
      <label className="flex items-center gap-2 text-base">
        <Checkbox defaultChecked />
        text-base
      </label>
      <label className="flex items-center gap-2.5 text-lg">
        <Checkbox defaultChecked />
        text-lg
      </label>
      <label className="flex items-center gap-3 text-xl">
        <Checkbox defaultChecked />
        text-xl
      </label>
    </div>
  )
}
```

### With a label and description [#with-a-label-and-description]

Put a title and supporting text beside the box. Keeping both inside the `<label>` means the whole block is one click target.

```tsx
import { Checkbox } from '@appica/ui-react/checkbox'

export default function CheckboxWithLabel() {
  return (
    <label className="flex max-w-sm items-start gap-2.5 select-none">
      <Checkbox defaultChecked className="mt-1" />
      <span className="flex flex-col">
        <span className="text-foreground-intense font-medium">Enable notifications</span>
        <span className="text-foreground-muted text-sm">
          Receive emails about new activity on your account. You can turn this off any time.
        </span>
      </span>
    </label>
  )
}
```

### Checkbox group [#checkbox-group]

`CheckboxGroup` shares a single array `value` across its children, so you read and set the whole set at once instead of tracking each box. Each child is matched to the value array by its `name`. It lays out vertically by default; pass `orientation="horizontal"` to wrap into a row.

```tsx
import { CheckboxGroup } from '@appica/ui-react/checkbox-group'
import { Checkbox } from '@appica/ui-react/checkbox'

const toppings = [
  { name: 'cheese', label: 'Extra cheese' },
  { name: 'mushrooms', label: 'Mushrooms' },
  { name: 'olives', label: 'Olives' },
  { name: 'onions', label: 'Onions' },
]

export default function CheckboxGroupExample() {
  return (
    <CheckboxGroup aria-labelledby="toppings-label" defaultValue={['cheese', 'olives']}>
      <span id="toppings-label" className="text-foreground mb-1 text-sm font-medium">
        Toppings
      </span>
      {toppings.map((topping) => (
        <label key={topping.name} className="flex items-center gap-2 text-sm select-none">
          <Checkbox name={topping.name} />
          {topping.label}
        </label>
      ))}
    </CheckboxGroup>
  )
}
```

### Select all (parent checkbox) [#select-all-parent-checkbox]

Give the group the full list of child values via `allValues` and mark one child `parent`. When some — but not all — children are checked, the group drives the parent into the `indeterminate` state automatically; ticking the parent checks every child, and clearing it unchecks them.

```tsx
'use client'

import * as React from 'react'
import { CheckboxGroup } from '@appica/ui-react/checkbox-group'
import { Checkbox } from '@appica/ui-react/checkbox'

const permissions = [
  { name: 'read', label: 'Read' },
  { name: 'write', label: 'Write' },
  { name: 'delete', label: 'Delete' },
]

const allValues = permissions.map((permission) => permission.name)

export default function CheckboxSelectAll() {
  const [value, setValue] = React.useState<string[]>(['read'])

  return (
    <CheckboxGroup aria-labelledby="permissions-label" allValues={allValues} value={value} onValueChange={setValue}>
      <label className="flex items-center gap-2 text-sm font-medium select-none">
        <Checkbox parent />
        <span id="permissions-label">Permissions</span>
      </label>
      <div className="flex flex-col gap-2 pl-6">
        {permissions.map((permission) => (
          <label key={permission.name} className="flex items-center gap-2 text-sm select-none">
            <Checkbox name={permission.name} />
            {permission.label}
          </label>
        ))}
      </div>
    </CheckboxGroup>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior — roving focus, popup placement, and the like — follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="checkbox" />

## API reference [#api-reference]

`Checkbox` and `CheckboxGroup` wrap [Base UI's Checkbox](https://base-ui.com/react/components/checkbox) and [CheckboxGroup](https://base-ui.com/react/components/checkbox-group). Each forwards `ref`, `aria-*`, and its native attributes; `Checkbox` exposes `data-*` state attributes (`data-checked`, `data-unchecked`, `data-indeterminate`, `data-disabled`, `data-readonly`, …) for styling and `CheckboxGroup` renders a `<div role="group">`. See the Base UI docs for the complete API.

### Checkbox [#checkbox]

| Prop              | <ColMinWidth width="200">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>                                                          |
| ----------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `checked`         | `boolean`                                                     | —       | Controlled checked state. Pair with `onCheckedChange`.                                                      |
| `defaultChecked`  | `boolean`                                                     | `false` | Uncontrolled initial checked state.                                                                         |
| `onCheckedChange` | <Code>(checked: boolean, details) => void</Code>              | —       | Fires when the box is ticked or unticked.                                                                   |
| `indeterminate`   | `boolean`                                                     | `false` | Render the mixed state (dash). Reported to assistive tech as `aria-checked="mixed"`.                        |
| `parent`          | `boolean`                                                     | `false` | Inside a `CheckboxGroup`, makes this the "select all" box driven by the children (needs group `allValues`). |
| `name`            | `string`                                                      | —       | Field name on form submit; also how a `CheckboxGroup` matches this box to its value array.                  |
| `value`           | `string`                                                      | —       | The value submitted with the form when the box is checked.                                                  |
| `uncheckedValue`  | `string`                                                      | —       | The value submitted with the form when the box is unchecked.                                                |
| `form`            | `string`                                                      | —       | `id` of the form that owns the hidden input, when it isn't a descendant.                                    |
| `disabled`        | `boolean`                                                     | `false` | Removes the box from the tab order and ignores interaction.                                                 |
| `readOnly`        | `boolean`                                                     | `false` | Focusable but not toggleable.                                                                               |
| `required`        | `boolean`                                                     | `false` | Must be checked before its form submits.                                                                    |
| `nativeButton`    | `boolean`                                                     | `false` | Whether the element passed to `render` is a native `<button>`.                                              |
| `inputRef`        | <Code>Ref\<HTMLInputElement></Code>                           | —       | Ref to the hidden `<input>` element backing the checkbox.                                                   |
| `id`              | `string`                                                      | —       | `id` of the rendered element.                                                                               |
| `render`          | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Replace the rendered element, or compose it with another component.                                         |
| `className`       | <Code>string \| ((state) => string)</Code>                    | —       | Extra classes on the box, merged via `tailwind-merge`. May be a function of state.                          |
| `style`           | <Code>CSSProperties \| ((state) => CSSProperties)</Code>      | —       | Inline styles, optionally derived from state.                                                               |

### CheckboxGroup [#checkboxgroup]

Shares one value array across the checkboxes nested inside it.

| Prop            | <ColMinWidth width="200">Type</ColMinWidth>                   | Default      | <ColMinWidth width="220">Description</ColMinWidth>                                    |
| --------------- | ------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------- |
| `value`         | `string[]`                                                    | —            | Controlled array of checked child `name`s. Pair with `onValueChange`.                 |
| `defaultValue`  | `string[]`                                                    | —            | Uncontrolled initial set of checked children.                                         |
| `onValueChange` | <Code>(value: string\[], details) => void</Code>              | —            | Fires with the next array whenever a child toggles.                                   |
| `allValues`     | `string[]`                                                    | —            | Every child value — required to drive a `parent` "select all" checkbox.               |
| `orientation`   | <Code>'horizontal' \| 'vertical'</Code>                       | `'vertical'` | Stack the boxes in a column, or wrap them into a row.                                 |
| `disabled`      | `boolean`                                                     | `false`      | Disables every checkbox in the group.                                                 |
| `render`        | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —            | Replace the group element, or compose it with another component.                      |
| `className`     | <Code>string \| ((state) => string)</Code>                    | —            | Extra classes, merged via `tailwind-merge` (override the default `flex` layout here). |
| `style`         | <Code>CSSProperties \| ((state) => CSSProperties)</Code>      | —            | Inline styles, optionally derived from state.                                         |

## Accessibility [#accessibility]

* Renders with `role="checkbox"`. **Space** toggles it; **Tab** moves focus to and from it.
* A checkbox needs an accessible name — wrap it in a `<label>` together with its text (as shown above), or give it an `aria-label`.
* `indeterminate` is announced as `aria-checked="mixed"`, distinct from checked and unchecked.
* `CheckboxGroup` renders a `<div role="group">`; name it with `aria-label` or `aria-labelledby` since a group can't use a wrapping `<label>`.
* `disabled` removes the box from the tab order and exposes `data-disabled` for styling.
* The check/squish animations honour `prefers-reduced-motion`.
