Skip to content

Checkbox

Lets the user turn a single option on or off, with an optional indeterminate state.

Inputv0.1.1experimentalWCAG 2.2 AAView spec
import { Checkbox } from "@rdloom/react";

export default function CheckboxBasicExample() {
  return (
    <Checkbox defaultSelected>Email me product updates</Checkbox>
  );
}

Installation

npx rdloom add checkbox

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/checkbox.json

Works, but without upgrade tracking.

Usage

import { Checkbox } from "@rdloom/react";

<Checkbox defaultSelected>Email me product updates</Checkbox>

Indeterminate

import { useState } from "react";
import { Checkbox } from "@rdloom/react";

const platforms = [
  { id: "web", name: "Web" },
  { id: "ios", name: "iOS" },
  { id: "android", name: "Android" },
];

export default function CheckboxIndeterminateExample() {
  const [checked, setChecked] = useState(["web"]);
  const all = checked.length === platforms.length;
  const some = checked.length > 0 && !all;
  return (
    <div className="flex flex-col gap-2">
      <Checkbox isSelected={all} isIndeterminate={some} onChange={(on) => setChecked(on ? platforms.map((p) => p.id) : [])}>
        All platforms
      </Checkbox>
      <div className="flex flex-col gap-2 ps-6">
        {platforms.map((p) => (
          <Checkbox
            key={p.id}
            isSelected={checked.includes(p.id)}
            onChange={(on) => setChecked(on ? [...checked, p.id] : checked.filter((c) => c !== p.id))}
          >
            {p.name}
          </Checkbox>
        ))}
      </div>
    </div>
  );
}

Invalid

import { Button, Checkbox } from "@rdloom/react";

export default function CheckboxInvalidExample() {
  return (
    <form className="flex flex-col items-start gap-3" onSubmit={(e) => e.preventDefault()}>
      {/* Submit without checking it to see the error. */}
      <Checkbox isRequired>I accept the terms</Checkbox>
      <Button type="submit">Continue</Button>
    </form>
  );
}

Disabled

import { Checkbox } from "@rdloom/react";

export default function CheckboxDisabledExample() {
  return (
    <div className="flex flex-col gap-2">
      <Checkbox isDisabled>Beta features</Checkbox>
      <Checkbox isDisabled defaultSelected>
        Required cookies
      </Checkbox>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

Visible label.

nodenone
isSelected

Controlled checked state.

booleannone
defaultSelected

Initial checked state when uncontrolled.

booleanfalse
isIndeterminate

Shows a dash for a partially selected group, e.g. 'select all'.

booleanfalse
isDisabled

Prevents interaction and dims the checkbox.

booleanfalse
isInvalid

Marks the checkbox as invalid, e.g. an unaccepted required agreement.

booleanfalse
onChange

Called with the new checked state.

(isSelected: boolean) => voidnone

Accessibility

Role checkbox, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Space toggles

Screen readers announce

  • Announced as a checkbox with its label and checked or not checked
  • Indeterminate is announced as half checked or mixed
  • Toggling announces the new state
  • Invalid is announced as invalid

What your code must do

  • Label is part of the click target
  • Indeterminate is exposed as aria-checked=mixed

Guidelines

Use it when

  • Independent on/off options in a form
  • Accepting terms
  • Selecting rows

Avoid it when

  • A setting that takes effect immediately: use Switch
  • Exactly one choice from a set: use RadioGroup

Don't

  • Negative labels like 'Don't send emails'
  • Passing isInvalid for required or format checks (even isInvalid={false}): any defined value takes over validity and hides the built-in errors. Use isRequired and validate; pass isInvalid only for errors the app finds itself, such as from the server

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-action-primary
  • --rd-color-action-on-primary
  • --rd-color-border-strong
  • --rd-color-surface-default
  • --rd-color-text-default
  • --rd-color-feedback-danger
  • --rd-color-focus-ring
  • --rd-radius-control