Wuko
Components

Checkbox

A control that toggles between checked, unchecked, and indeterminate states. Built on Radix Checkbox for full keyboard accessibility, with aria-invalid styling for form validation. For form-submitted boolean inputs, use Checkbox. For instant-action toggles (e.g., enable a feature), prefer Toggle.

Installation

terminal
npx shadcn@latest add @wuko/checkbox

Usage

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

export function Example() {
  return (
    <label className="flex items-center gap-2">
      <Checkbox />
      Accept terms and conditions
    </label>
  );
}

Checked state

Use defaultChecked for uncontrolled checkboxes, or checked and onCheckedChange to control the state.

tsx
"use client";

import * as React from "react";
import { Checkbox } from "@/components/ui/checkbox";

export function Example() {
  const [checked, setChecked] = React.useState(false);

  return <Checkbox checked={checked} onCheckedChange={setChecked} />;
}

Indeterminate

Set checked="indeterminate" for a third state — useful when a parent checkbox represents partial selection of its children (e.g., a header checkbox controlling some-but-not-all selected rows).

tsx
<Checkbox checked="indeterminate" />

Invalid state

Set aria-invalid="true" to indicate a validation error. The border and focus ring turn red.

tsx
<label className="flex items-center gap-2">
  <Checkbox aria-invalid="true" />
  Accept terms and conditions
</label>

Disabled

Use the disabled prop to prevent interaction. Pair with muted label styling for context.

tsx
<label className="flex items-center gap-2 opacity-50">
  <Checkbox disabled />
  Enable notifications
</label>

Group

Use multiple labeled checkboxes under a shared heading for selection lists. Each maintains independent state.

Show these items on the desktop:
tsx
"use client";

import * as React from "react";
import { Checkbox } from "@/components/ui/checkbox";

export function Example() {
  const [items, setItems] = React.useState({
    hardDisks: true,
    externalDisks: false,
    cdsDvds: false,
    servers: true,
  });

  return (
    <div className="flex flex-col gap-3">
      <div className="text-sm font-medium">Show these items on the desktop:</div>
      {Object.entries(items).map(([key, value]) => (
        <label key={key} className="flex items-center gap-2 text-sm">
          <Checkbox
            checked={value}
            onCheckedChange={(v) => setItems({ ...items, [key]: v === true })}
          />
          {key}
        </label>
      ))}
    </div>
  );
}

Props

Forwards all props to the underlying Radix Checkbox. The most commonly used props are listed below.

PropTypeDefaultDescription
checkedboolean | "indeterminate"falseControlled checked state. Use the literal string "indeterminate" for the third state.
defaultCheckedbooleanfalseInitial checked state for uncontrolled use. Use checked + onCheckedChange for controlled state.
onCheckedChange(checked: boolean | "indeterminate") => voidFires when the checked state changes.
disabledbooleanfalseDisables interaction and reduces opacity.
requiredbooleanfalseMarks the checkbox as required for form submission.
aria-invalidboolean | "true" | "false"When true, applies the invalid state styling (red border, red focus ring).
namestringThe name attribute submitted with form data.
valuestring"on"The value submitted with form data when checked.
classNamestringAdditional Tailwind classes merged with defaults.

Accessibility

  • Built on Radix Checkbox. Keyboard support: Tab to focus, Space to toggle. Screen readers announce checked, unchecked, and indeterminate states.
  • Wrap each checkbox in a <label> with associated text. Clicking the label toggles the checkbox and screen readers announce the label as the checkbox's name.
  • For invalid state, set aria-invalid="true". The styling change is paired with the ARIA attribute so screen readers announce the validation state.
  • The peer utility on the underlying Radix Root lets you style sibling elements based on checkbox state (e.g., peer-disabled:opacity-50 on a label).
  • For checkboxes in form submissions, set the name prop. The value (default "on") is submitted when checked.