import { Checkbox } from "@registry/components/ui/checkbox";

export function CheckboxExample() {
  return (
    <div className="flex items-center gap-4">
      <Checkbox />
    </div>
  );
}

Examples

Default checked

Use defaultChecked to set the initial state without controlling the component.

import { Checkbox } from "@registry/components/ui/checkbox";

export function CheckboxCheckedExample() {
  return (
    <div className="flex items-center gap-4">
      <Checkbox defaultChecked />
    </div>
  );
}

Disabled

Use the disabled prop to prevent interaction.

import { Checkbox } from "@registry/components/ui/checkbox";

export function CheckboxDisabledExample() {
  return (
    <div className="flex items-center gap-4">
      <Checkbox disabled />
      <Checkbox defaultChecked disabled />
    </div>
  );
}

Controlled

Manage the checked state with React state using checked and onCheckedChange.

Unchecked
import { useState } from "react";
import { Checkbox } from "@registry/components/ui/checkbox";

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

  return (
    <div className="flex items-center gap-4">
      <Checkbox checked={checked} onCheckedChange={setChecked} />
      <span className="text-sm text-gray-600 dark:text-gray-400">
        {checked ? "Checked" : "Unchecked"}
      </span>
    </div>
  );
}

Group

Use CheckboxGroup to manage multiple related checkboxes. Each child checkbox uses a value prop that matches the group’s value array.

import { Checkbox, CheckboxGroup } from "@registry/components/ui/checkbox";

export function CheckboxGroupExample() {
  return (
    <CheckboxGroup defaultValue={["design"]}>
      <label className="flex items-center gap-2 text-sm">
        <Checkbox value="design" />
        <span className="text-gray-900 dark:text-gray-100">Design</span>
      </label>
      <label className="flex items-center gap-2 text-sm">
        <Checkbox value="engineering" />
        <span className="text-gray-900 dark:text-gray-100">Engineering</span>
      </label>
      <label className="flex items-center gap-2 text-sm">
        <Checkbox value="marketing" />
        <span className="text-gray-900 dark:text-gray-100">Marketing</span>
      </label>
    </CheckboxGroup>
  );
}

Controlled group

Manage the group’s selected values with React state using value and onValueChange.

Selected: design
import { useState } from "react";
import { Checkbox, CheckboxGroup } from "@registry/components/ui/checkbox";

export function CheckboxGroupControlledExample() {
  const [value, setValue] = useState<string[]>(["design"]);

  return (
    <div className="flex flex-col gap-3">
      <CheckboxGroup value={value} onValueChange={setValue}>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="design" />
          <span className="text-gray-900 dark:text-gray-100">Design</span>
        </label>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="engineering" />
          <span className="text-gray-900 dark:text-gray-100">Engineering</span>
        </label>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="marketing" />
          <span className="text-gray-900 dark:text-gray-100">Marketing</span>
        </label>
      </CheckboxGroup>
      <span className="text-sm text-gray-600 dark:text-gray-400">
        Selected: {value.join(", ") || "None"}
      </span>
    </div>
  );
}

Parent checkbox

Use a parent checkbox with the parent prop to control a group of child checkboxes. Pass allValues to CheckboxGroup so the parent can toggle all children. The parent automatically shows an indeterminate state when some children are selected.

import { useState } from "react";
import { Checkbox, CheckboxGroup } from "@registry/components/ui/checkbox";

export function CheckboxGroupIndeterminateExample() {
  const allValues = ["fuji", "gala", "granny-smith"];
  const [value, setValue] = useState<string[]>([]);

  return (
    <CheckboxGroup value={value} onValueChange={setValue} allValues={allValues}>
      <label className="flex items-center gap-2 text-sm font-medium">
        <Checkbox parent />
        <span className="text-gray-900 dark:text-gray-100">Apples</span>
      </label>
      <div className="flex flex-col gap-2 pl-4">
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="fuji" />
          <span className="text-gray-900 dark:text-gray-100">Fuji</span>
        </label>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="gala" />
          <span className="text-gray-900 dark:text-gray-100">Gala</span>
        </label>
        <label className="flex items-center gap-2 text-sm">
          <Checkbox value="granny-smith" />
          <span className="text-gray-900 dark:text-gray-100">Granny Smith</span>
        </label>
      </div>
    </CheckboxGroup>
  );
}

Installation

Copy the source code below into your project:

import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
import { CheckboxGroup as BaseCheckboxGroup } from "@base-ui/react/checkbox-group";
import { cn } from "@registry/lib/utils";
import { AnimatePresence, motion } from "motion/react";

function CheckboxGroup({ className, ...props }: BaseCheckboxGroup.Props) {
  return (
    <BaseCheckboxGroup
      className={cn("flex flex-col gap-2", className)}
      data-slot="checkbox-group"
      {...props}
    />
  );
}

function Checkbox({ className, ...props }: BaseCheckbox.Root.Props) {
  return (
    <BaseCheckbox.Root
      className={cn(
        "data-disabled:pointer-not-allowed relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-sm border border-input bg-muted ring-ring outline-none before:pointer-events-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-50 sm:size-4 dark:not-data-checked:bg-gray-950/32 dark:aria-invalid:ring-destructive/24",
        "data-checked:bg-accent data-indeterminate:bg-accent",
        className,
      )}
      data-slot="checkbox"
      {...props}
    >
      <BaseCheckbox.Indicator
        className="absolute inset-0 flex items-center justify-center rounded-sm"
        data-slot="checkbox-indicator"
        keepMounted
        render={(props, state) => (
          <span {...props}>
            <AnimatePresence initial={false}>
              {(state.checked || state.indeterminate) && (
                <motion.span
                  animate={{ filter: "blur(0px)", opacity: 1, scale: 1 }}
                  className="absolute inset-0 flex items-center justify-center text-accent-foreground"
                  exit={{ filter: "blur(2px)", opacity: 0, scale: 0.8 }}
                  initial={{ filter: "blur(2px)", opacity: 0, scale: 0.8 }}
                  key={state.indeterminate ? "indeterminate" : "checked"}
                  transition={{ duration: 0.2, ease: [0.86, 0, 0.07, 1] }}
                >
                  {state.indeterminate ? <IndeterminateIcon /> : <CheckmarkIcon />}
                </motion.span>
              )}
            </AnimatePresence>
          </span>
        )}
      />
    </BaseCheckbox.Root>
  );
}

function CheckmarkIcon() {
  return (
    <motion.svg aria-hidden="true" className="size-3.5 sm:size-3" fill="none" viewBox="0 0 14 14">
      <motion.path
        animate={{ pathLength: 1 }}
        d="M3 7.25L5.75 10L11 4"
        initial={{ pathLength: 0 }}
        stroke="currentColor"
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth="1.5"
        transition={{ duration: 0.2, ease: [0.86, 0, 0.07, 1] }}
      />
    </motion.svg>
  );
}

function IndeterminateIcon() {
  return (
    <motion.svg aria-hidden="true" className="size-3.5 sm:size-3" fill="none" viewBox="0 0 14 14">
      <motion.path
        animate={{ pathLength: 1 }}
        d="M3.5 7H10.5"
        initial={{ pathLength: 0 }}
        stroke="currentColor"
        strokeLinecap="round"
        strokeWidth="1.5"
        transition={{ duration: 0.2, ease: [0.86, 0, 0.07, 1] }}
      />
    </motion.svg>
  );
}

export { CheckboxGroup, Checkbox };

API Reference

Checkbox

This component does not add any props on top of Base UI Checkbox.Root . See the Base UI docs for the full API reference.

CheckboxGroup

This component does not add any props on top of Base UI CheckboxGroup . See the Base UI docs for the full API reference.