IndiaCN UI

Checkbox

A tri-state checkbox for opting in, out, or partially selecting.

Introduction

Checkboxes let people select one or more options, or confirm a single choice. Alongside checked and unchecked, they support an indeterminate state for parent options whose children are partially selected. Built on Radix UI's Checkbox primitive, so keyboard interaction and ARIA state are handled for you.

Installation

npx shadcn@latest add https://indiacn.in/r/checkbox.json
import { Checkbox } from '@/components/ui/checkbox';

Usage

<div className="flex items-center gap-3">
<Checkbox id="terms" defaultChecked />
<Label htmlFor="terms">Accept terms and conditions</Label>
</div>

Examples

Default

CheckboxDefault
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';

export default function Component() {
  return (
    <div className='flex items-center gap-3'>
      <Checkbox id='terms' defaultChecked />
      <Label htmlFor='terms'>Accept terms and conditions</Label>
    </div>
  );
}

States

All three types across enabled and disabled.

CheckboxStates
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';

export default function Component() {
  return (
    <div className='grid gap-4'>
      <div className='flex items-center gap-3'>
        <Checkbox id='state-checked' defaultChecked />
        <Label htmlFor='state-checked'>Checked</Label>
      </div>
      <div className='flex items-center gap-3'>
        <Checkbox id='state-indeterminate' checked='indeterminate' />
        <Label htmlFor='state-indeterminate'>Indeterminate</Label>
      </div>
      <div className='flex items-center gap-3'>
        <Checkbox id='state-unchecked' />
        <Label htmlFor='state-unchecked'>Unchecked</Label>
      </div>
      <div className='flex items-center gap-3'>
        <Checkbox id='state-disabled' disabled defaultChecked />
        <Label htmlFor='state-disabled'>Disabled</Label>
      </div>
    </div>
  );
}

Controlled Group

1 document selected

CheckboxGroup
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';

const DOCUMENTS = ['Aadhaar', 'PAN card', 'Driving licence'];

interface IDocumentOptionProps {
  document: string;
  checked: boolean;
  onToggle: (document: string) => void;
}

/** Single checkbox row within the controlled group example. */
function DocumentOption({ document, checked, onToggle }: IDocumentOptionProps) {
  const handleCheckedChange = useCallback(() => onToggle(document), [document, onToggle]);

  return (
    <div className='flex items-center gap-3'>
      <Checkbox id={document} checked={checked} onCheckedChange={handleCheckedChange} />
      <Label htmlFor={document}>{document}</Label>
    </div>
  );
}

export default function Component() {
  const [selected, setSelected] = useState<string[]>(['Aadhaar']);

  const handleToggle = useCallback((document: string) => {
    setSelected((current) =>
      current.includes(document)
        ? current.filter((entry) => entry !== document)
        : [...current, document],
    );
  }, []);

  return (
    <div className='grid gap-3'>
      {DOCUMENTS.map((document) => (
        <DocumentOption
          key={document}
          document={document}
          checked={selected.includes(document)}
          onToggle={handleToggle}
        />
      ))}
      <Body3 className='text-neutral-500'>
        {selected.length} document{selected.length === 1 ? '' : 's'} selected
      </Body3>
    </div>
  );
}

Accessibility

  • Toggles with Space and is reachable with Tab.
  • Pair every checkbox with a Label whose htmlFor matches the checkbox id, so the label is a click target and is announced by screen readers.
  • The focus ring is 4px at 48% primary, which clears WCAG AA against both themes.

API Reference

Checkbox

PropTypeDefaultDescription
checkedboolean | 'indeterminate'Controlled state. Pass 'indeterminate' for a partial selection
defaultCheckedbooleanfalseInitial state when uncontrolled
onCheckedChange(checked: boolean | 'indeterminate') => voidFires when the state changes
disabledbooleanfalsePrevents interaction and dims to 38%
requiredbooleanfalseMarks the field as required in a form
namestringName submitted with the parent form
valuestring'on'Value submitted when checked
classNamestringExtra Tailwind classes

On this page