Native Solid 2 fork. Original documentation and designs © WorkOS; historical posts retain their original context.

Checkbox

A control that allows the user to toggle between checked and not checked.

Download runnable sandbox
import { Checkbox } from "@radix-solid/primitives";
import { CheckIcon } from "@radix-solid/icons";
import styles from "./styles.module.css";
const CheckboxDemo = () => <form>
<div style={{ "display": "flex", "align-items": "center" }}>
<Checkbox.Root class={styles.Root} defaultChecked id="c1">
<Checkbox.Indicator class={styles.Indicator}>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Root>
<label class={styles.Label} for="c1">
Accept terms and conditions.
</label>
</div>
</form>;
export default CheckboxDemo;

Features

  • Supports indeterminate state.

  • Full keyboard navigation.

  • Can be controlled or uncontrolled.

Anatomy

Import all parts and piece them together.

import { Checkbox } from "@radix-solid/primitives";
export default () => <Checkbox.Root>
<Checkbox.Indicator />
</Checkbox.Root>;

API Reference

Root

Contains all the parts of a checkbox. An input will also render when used within a form to ensure events propagate correctly.

PropTypeDefault
asChildbooleanfalse
defaultCheckedboolean | 'indeterminate'—
checkedboolean | 'indeterminate'—
onCheckedChangefunction—
disabledboolean—
requiredboolean—
namestring—
valuestringon
Data attributeValues
[data-state]"checked" | "unchecked" | "indeterminate"
[data-disabled]

Present when disabled

Indicator

Renders when the checkbox is in a checked or indeterminate state. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.

PropTypeDefault
asChildbooleanfalse
forceMountboolean—
Data attributeValues
[data-state]"checked" | "unchecked" | "indeterminate"
[data-disabled]

Present when disabled

Examples

Indeterminate

You can set the checkbox to indeterminate by taking control of its state.

import { createSignal } from "solid-js";
import { DividerHorizontalIcon, CheckIcon } from "@radix-solid/icons";
import { Checkbox } from "@radix-solid/primitives";
export default () => {
const [checked, setChecked] = createSignal<boolean | "indeterminate">("indeterminate");
return <>
<Checkbox.Root aria-label="Select all" checked={checked()} onCheckedChange={setChecked}>
<Checkbox.Indicator>
{checked() === "indeterminate" && <DividerHorizontalIcon />}
{checked() === true && <CheckIcon />}
</Checkbox.Indicator>
</Checkbox.Root>
<button type="button" onClick={() => setChecked(prevIsChecked => prevIsChecked === "indeterminate" ? false : "indeterminate")}>
Toggle indeterminate
</button>
</>;
};

Decoupling the hidden input

By default, Checkbox.Root renders a visually hidden input for form submission. To recompose, move, or exclude that input, you can build the checkbox from its lower-level parts instead.

Important: These parts are unstable and prefixed with unstable_, so their API may change in a future release.

  • Checkbox.unstable_Provider provides the checkbox state and accepts the form-related props (name, value, checked, defaultChecked, required, disabled, onCheckedChange).
  • Checkbox.unstable_Trigger is the interactive button that wraps Checkbox.Indicator.
  • Checkbox.unstable_BubbleInput is the visually hidden input that Checkbox.Root renders by default. Omit it when you don't need form submission.
import { Checkbox } from "@radix-solid/primitives";
export default () => <Checkbox.unstable_Provider name="terms">
<Checkbox.unstable_Trigger>
<Checkbox.Indicator />
</Checkbox.unstable_Trigger>
<Checkbox.unstable_BubbleInput />
</Checkbox.unstable_Provider>;

Accessibility

Adheres to the tri-state Checkbox WAI-ARIA design pattern.

Keyboard Interactions

KeyDescription
Space
Checks/unchecks the checkbox.