# Checkbox (/docs/checkbox)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/checkbox" />

## Basic [#basic]

<Preview cssProperties="checkboxPlaygroundCssProperties">
  <CheckboxExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";

          export function CheckboxDemo() {
            return (
              <CheckboxField>
                <Checkbox defaultChecked />
                <CheckboxLabel>Enable notifications</CheckboxLabel>
              </CheckboxField>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSSProperties>
    {(context) => <CheckboxCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <CheckboxCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Composition [#composition]

`Checkbox` forwards Base UI root props and includes the indicator by default. Use it
uncontrolled with `defaultChecked`, controlled with `checked` and `onCheckedChange`, or
connect it to forms with `name`, `value`, `uncheckedValue`, `form`, `required`, `readOnly`,
and `inputRef`. It also supports Base UI composition props such as `render` and
`nativeButton`.

Pass `className` to style the root control. Use `classNames` to style the automatically
rendered indicator parts. Use `slotProps.indicator` for Base UI indicator props such as
`keepMounted`, `render`, and state-aware `style`. Compose `CheckboxIndicator` and
`CheckboxIndicatorIcon` yourself only when you need full control over the indicator slot:

```tsx
<Checkbox
  className={styles.checkbox}
  classNames={{
    indicator: styles.indicator,
    indicatorIcon: styles.indicatorIcon,
    checkedIcon: styles.checkedIcon,
    indeterminateIcon: styles.indeterminateIcon,
  }}
  slotProps={{
    indicator: { keepMounted: true },
  }}
/>
```

## Anatomy [#anatomy]

Checkbox is composed around one interactive root and optional label wrappers. Use
`CheckboxField` and `CheckboxLabel` for the common clickable-label pattern, and keep
them grouped so focus, disabled state, and text association stay aligned.

```text
CheckboxField
├─ Checkbox
│  └─ CheckboxIndicator
│     └─ CheckboxIndicatorIcon
└─ CheckboxLabel
```

```tsx
<CheckboxField>
  <Checkbox defaultChecked>
    <CheckboxIndicator>
      <CheckboxIndicatorIcon />
    </CheckboxIndicator>
  </Checkbox>
  <CheckboxLabel>Enable notifications</CheckboxLabel>
</CheckboxField>
```

| Part                    | Role                                                                                                   |
| ----------------------- | ------------------------------------------------------------------------------------------------------ |
| `Checkbox`              | Interactive root. Controls checked, indeterminate, and disabled states and exposes styling attributes. |
| `CheckboxIndicator`     | Indicator slot inside the root. Renders automatically by default, or can be composed manually.         |
| `CheckboxIndicatorIcon` | Icon slot inside the indicator. Switches between checked and indeterminate visuals by state.           |
| `CheckboxField`         | Optional wrapper that groups the checkbox and label into one accessible field pattern.                 |
| `CheckboxLabel`         | Optional text label associated with the checkbox for pointer and keyboard interaction.                 |

`Checkbox` does not use service slots such as `portal`, `backdrop`, or `viewport`.
In most cases, keep behavior defaults and customize visible slots via `className`,
`classNames`, and CSS variables.

## Examples [#examples]

### Indeterminate [#indeterminate]

Use `indeterminate` when a parent option represents a mixed selection state.

<Preview>
  <CheckboxIndeterminateExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";

          export function IndeterminateCheckboxDemo() {
            return (
              <CheckboxField>
                <Checkbox indeterminate />
                <CheckboxLabel>Select all team members</CheckboxLabel>
              </CheckboxField>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Sizes [#sizes]

Use `size` to align the control with different form densities.

<Preview>
  <CheckboxSizesExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";

          export function CheckboxSizesDemo() {
            return (
              <div className={styles.stack}>
                <CheckboxField>
                  <Checkbox size="xs" defaultChecked />
                  <CheckboxLabel>Extra-small</CheckboxLabel>
                </CheckboxField>
                <CheckboxField>
                  <Checkbox size="sm" defaultChecked />
                  <CheckboxLabel>Small</CheckboxLabel>
                </CheckboxField>
                <CheckboxField>
                  <Checkbox size="md" defaultChecked />
                  <CheckboxLabel>Medium</CheckboxLabel>
                </CheckboxField>
                <CheckboxField>
                  <Checkbox size="lg" defaultChecked />
                  <CheckboxLabel>Large</CheckboxLabel>
                </CheckboxField>
                <CheckboxField>
                  <Checkbox size="xl" defaultChecked />
                  <CheckboxLabel>Extra-large</CheckboxLabel>
                </CheckboxField>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Disabled [#disabled]

Use `disabled` to prevent interaction while preserving the selection state in the UI.

<Preview>
  <CheckboxDisabledExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";

          export function DisabledCheckboxDemo() {
            return (
              <div className={styles.stack}>
                <CheckboxField>
                  <Checkbox disabled />
                  <CheckboxLabel>Receive weekly summary</CheckboxLabel>
                </CheckboxField>
                <CheckboxField>
                  <Checkbox defaultChecked disabled />
                  <CheckboxLabel>Share anonymous usage data</CheckboxLabel>
                </CheckboxField>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Controlled [#controlled]

Control `checked` from React state when the checkbox needs to coordinate with other UI.

<Preview>
  <ControlledCheckboxExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";
          import { useState } from "react";

          export function ControlledCheckboxDemo() {
            const [checked, setChecked] = useState(false);

            return (
              <div className={styles.stack}>
                <CheckboxField>
                  <Checkbox checked={checked} onCheckedChange={setChecked} />
                  <CheckboxLabel>{checked ? "Enabled" : "Disabled"}</CheckboxLabel>
                </CheckboxField>
                <span className={styles.hint}>Current value: {String(checked)}</span>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }

          .hint {
            color: var(--color-muted-foreground);
            font-size: var(--text-xs);
            line-height: var(--line-height-text-xs);
          }
        `}
  </Preview.CSS>
</Preview>

### Indicator Icon [#indicator-icon]

Pass icon nodes to `checkedIcon` and `indeterminateIcon`, or compose `CheckboxIndicator` directly when you need full control over the indicator slot.

<Preview>
  <CustomIconCheckboxExample />

  <Preview.Code>
    {`
          import {
            Checkbox,
            CheckboxField,
            CheckboxLabel,
          } from "moduix";
          import type { ComponentProps } from "react";

          function CustomPlusIcon(props: ComponentProps<"svg">) {
            return (
              <svg viewBox="0 0 10 10" fill="none" aria-hidden="true" focusable="false" {...props}>
                <path
                  d="M5 1.5V8.5M1.5 5H8.5"
                  stroke="currentColor"
                  strokeWidth="1.8"
                  strokeLinecap="round"
                />
              </svg>
            );
          }

          export function IndicatorIconCheckboxDemo() {
            return (
              <CheckboxField>
                <Checkbox defaultChecked checkedIcon={<CustomPlusIcon />} />
                <CheckboxLabel>Use custom indicator icon</CheckboxLabel>
              </CheckboxField>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Custom Styles [#custom-styles]

Pass `className` to the field, root, and label slots. Use `classNames` for the automatically rendered indicator slots.

<Preview>
  <CustomStylesCheckboxExample />

  <Preview.Code>
    {`
          import { Checkbox, CheckboxField, CheckboxLabel } from "moduix";

          export function CustomStylesCheckboxDemo() {
            return (
              <CheckboxField className={styles.customField}>
                <Checkbox
                  className={styles.customCheckbox}
                  classNames={{
                    indicator: styles.customIndicator,
                    indicatorIcon: styles.customIndicatorIcon,
                    checkedIcon: styles.customCheckedIcon,
                    indeterminateIcon: styles.customIndeterminateIcon,
                  }}
                  defaultChecked
                />
                <CheckboxLabel className={styles.customLabel}>Styled with className</CheckboxLabel>
              </CheckboxField>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customField {
            gap: var(--spacing-3);
          }

          .customCheckbox {
            border-color: var(--color-primary);

            &[data-checked] {
              background-color: var(--color-primary);
            }
          }

          .customIndicator {
            color: var(--color-primary-foreground);
          }

          .customIndicatorIcon {
            transform: rotate(-8deg);
          }

          .customCheckedIcon {
            filter: drop-shadow(0 0 0.25rem rgb(255 255 255 / 0.4));
          }

          .customIndeterminateIcon {
            opacity: 0.86;
          }

          .customLabel {
            color: var(--color-primary);
          }
        `}
  </Preview.CSS>
</Preview>

### Sibling Label [#sibling-label]

Use `nativeButton` with `render={<button />}` for the sibling `label` pattern with `htmlFor` and `id`.

<Preview>
  <CheckboxSiblingLabelNativeButtonExample />

  <Preview.Code>
    {`
          import { Checkbox } from "moduix";
          import { useId } from "react";

          export function SiblingLabelCheckboxDemo() {
            const id = useId();

            return (
              <div className={styles.siblingRow}>
                <Checkbox nativeButton render={<button />} id={id} defaultChecked />
                <label htmlFor={id} className={styles.label}>
                  Keep me signed in
                </label>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .siblingRow {
            display: flex;
            align-items: center;
            gap: var(--checkbox-gap, var(--spacing-2));
          }

          .label {
            color: var(--checkbox-label-color, var(--color-foreground));
            font-size: var(--checkbox-label-font-size, var(--text-sm));
            font-weight: var(--checkbox-label-font-weight, var(--weight-medium));
            line-height: var(--checkbox-label-line-height, var(--line-height-text-sm));
          }
        `}
  </Preview.CSS>
</Preview>
