ComponentsCheckbox

Checkbox

A customizable checkbox component with support for indeterminate state, built on Base UI primitives.

Features

  • Base UI Integration: Built on Base UI Checkbox primitives for accessibility
  • Indeterminate State: Support for partial selection states
  • Multiple Sizes: Small, default, and large sizes
  • Field Integration: Works with labels and descriptions
  • Custom Icons: Support for custom check and indeterminate icons
  • Dark Mode: Automatically adapts to light and dark themes

Installation

npm install @bao-ui/react

Usage

Basic Checkbox

import { Checkbox } from '@bao-ui/react'
 
function Example() {
  return <Checkbox label="Accept terms and conditions" />
}

With Description

import { Checkbox } from '@bao-ui/react'
 
function Example() {
  return (
    <Checkbox
      label="Send me notifications"
      description="Get notified about updates and news."
    />
  )
}

Controlled Checkbox

import { useState } from 'react'
import { Checkbox } from '@bao-ui/react'
 
function Example() {
  const [checked, setChecked] = useState(false)
 
  return (
    <div className="space-y-4">
      <Checkbox
        label="Controlled checkbox"
        checked={checked}
        onCheckedChange={setChecked}
        description={`Checkbox is ${checked ? 'checked' : 'unchecked'}`}
      />
      <button
        onClick={() => setChecked(!checked)}
        className="rounded bg-secondary px-3 py-1 text-sm hover:bg-secondary/80"
      >
        Toggle Checkbox
      </button>
    </div>
  )
}

Sizes

import { Checkbox } from '@bao-ui/react'
 
function Example() {
  return (
    <div className="space-y-4">
      <Checkbox size="sm" label="Small checkbox" />
      <Checkbox size="default" label="Default checkbox" />
      <Checkbox size="lg" label="Large checkbox" />
    </div>
  )
}

States

import { Checkbox } from '@bao-ui/react'
 
function Example() {
  return (
    <div className="space-y-4">
      <Checkbox label="Default state" />
      <Checkbox label="Checked state" defaultChecked />
      <Checkbox label="Indeterminate state" indeterminate />
      <Checkbox label="Disabled state" disabled />
      <Checkbox label="Disabled checked" disabled defaultChecked />
    </div>
  )
}

Checkbox Group

import { useState } from 'react'
import { Checkbox } from '@bao-ui/react'
 
function Example() {
  const [selectedItems, setSelectedItems] = useState(['option1'])
 
  const handleChange = (value, checked) => {
    if (checked) {
      setSelectedItems([...selectedItems, value])
    } else {
      setSelectedItems(selectedItems.filter(item => item !== value))
    }
  }
 
  return (
    <div className="space-y-3">
      <h3 className="text-sm font-medium">Select your preferences:</h3>
      <Checkbox
        label="Email notifications"
        checked={selectedItems.includes('option1')}
        onCheckedChange={checked => handleChange('option1', checked)}
        description="Receive updates via email"
      />
      <Checkbox
        label="SMS notifications"
        checked={selectedItems.includes('option2')}
        onCheckedChange={checked => handleChange('option2', checked)}
        description="Receive updates via SMS"
      />
      <Checkbox
        label="Push notifications"
        checked={selectedItems.includes('option3')}
        onCheckedChange={checked => handleChange('option3', checked)}
        description="Receive push notifications"
      />
      <div className="mt-4 text-sm text-muted-foreground">
        Selected: {selectedItems.length > 0 ? selectedItems.join(', ') : 'None'}
      </div>
    </div>
  )
}

Parent-Child Checkboxes

import { useState } from 'react'
import { Checkbox } from '@bao-ui/react'
 
function Example() {
  const [parentChecked, setParentChecked] = useState(false)
  const [childStates, setChildStates] = useState({
    child1: false,
    child2: false,
    child3: false,
  })
 
  const childCount = Object.values(childStates).filter(Boolean).length
  const totalChildren = Object.keys(childStates).length
  const isIndeterminate = childCount > 0 && childCount < totalChildren
 
  const handleParentChange = checked => {
    setParentChecked(checked)
    setChildStates({
      child1: checked,
      child2: checked,
      child3: checked,
    })
  }
 
  const handleChildChange = (childKey, checked) => {
    const newChildStates = { ...childStates, [childKey]: checked }
    setChildStates(newChildStates)
 
    const newChildCount = Object.values(newChildStates).filter(Boolean).length
    setParentChecked(newChildCount === totalChildren)
  }
 
  return (
    <div className="space-y-3">
      <Checkbox
        label="Select all features"
        checked={parentChecked}
        indeterminate={isIndeterminate}
        onCheckedChange={handleParentChange}
        description="Toggle all features on or off"
      />
      <div className="ml-6 space-y-2">
        <Checkbox
          label="Feature A"
          checked={childStates.child1}
          onCheckedChange={checked => handleChildChange('child1', checked)}
        />
        <Checkbox
          label="Feature B"
          checked={childStates.child2}
          onCheckedChange={checked => handleChildChange('child2', checked)}
        />
        <Checkbox
          label="Feature C"
          checked={childStates.child3}
          onCheckedChange={checked => handleChildChange('child3', checked)}
        />
      </div>
    </div>
  )
}

Custom Composition

For advanced use cases, you can compose the checkbox using individual components:

import {
  CheckboxFieldRoot,
  CheckboxRoot,
  CheckboxIndicator,
  CheckboxLabel,
  CheckboxDescription,
} from '@bao-ui/react'
 
function Example() {
  return (
    <CheckboxFieldRoot>
      <div className="flex items-center space-x-3">
        <CheckboxRoot defaultChecked>
          <CheckboxIndicator />
        </CheckboxRoot>
        <div>
          <CheckboxLabel>Custom composed checkbox</CheckboxLabel>
          <CheckboxDescription>
            This uses individual components for maximum flexibility.
          </CheckboxDescription>
        </div>
      </div>
    </CheckboxFieldRoot>
  )
}

API Reference

Checkbox

PropTypeDefaultDescription
labelstring-Label text for the checkbox
descriptionstring-Helper text below the checkbox
indeterminatebooleanfalseWhether the checkbox is in indeterminate state
size'sm' | 'default' | 'lg''default'Size of the checkbox
checkedboolean-Controlled checked state
defaultCheckedbooleanfalseDefault checked state
onCheckedChange(checked: boolean) => void-Callback when checked state changes
disabledbooleanfalseWhether the checkbox is disabled
classNamestring-Additional CSS classes

Individual Components

CheckboxRoot

The root checkbox element (button).

PropTypeDefaultDescription
size'sm' | 'default' | 'lg''default'Size of the checkbox
classNamestring-Additional CSS classes

CheckboxIndicator

The visual indicator (checkmark/dash).

PropTypeDefaultDescription
classNamestring-Additional CSS classes

CheckboxFieldRoot

Container component for field composition.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

CheckboxLabel

Label component for the checkbox.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

CheckboxDescription

Description component for the checkbox.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

Accessibility

The Checkbox component follows WAI-ARIA guidelines:

  • Proper ARIA attributes (aria-checked, aria-labelledby)
  • Keyboard navigation support (Space to toggle)
  • Screen reader announcements for state changes
  • Focus management and visual indicators
  • Support for indeterminate state announcements

Keyboard Shortcuts

  • Space - Toggle the checkbox
  • Tab - Move focus to the checkbox
  • Shift + Tab - Move focus away from the checkbox

Dark Mode

The Checkbox component automatically adapts to your theme:

  • Uses semantic color tokens
  • Supports both system preference and manual theme switching
  • Maintains proper contrast ratios in all themes