UIUpdated May 11, 2026

Checkbox

Boolean selection control for settings, forms, filters, consent, and multi-select product flows in PyColors UI.

UICheckbox

Boolean choices for forms and product settingsLink to section

The Checkbox component lets users select one or more options from a list, confirm a setting, or opt into a specific condition.

Use it for:

  • settings toggles that can be selected independently
  • multi-select filters
  • terms, consent, and confirmation fields
  • grouped preferences
  • checklist-style product flows
  • optional form choices

Checkbox is built on Radix Checkbox and styled with PyColors semantic tokens such as border-input, bg-background, text-foreground, and ring-ring.

Core idea

Checkbox is for explicit selection. Use it when each option can be independently checked or unchecked.

ImportLink to section

checkbox-import.tsx
import { Checkbox } from "@pycolors/ui";

Basic usageLink to section

Use a Checkbox with a label when the user needs to enable or select one option.

Collect product usage data to improve the dashboard experience.

basic-checkbox.tsx
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

export function BasicCheckbox() {
  return (
    <CheckboxField>
      <Checkbox id="analytics" />
      <CheckboxContent>
        <CheckboxLabel htmlFor="analytics">
          Enable analytics
        </CheckboxLabel>
        <CheckboxDescription>
          Collect product usage data to improve the dashboard experience.
        </CheckboxDescription>
      </CheckboxContent>
    </CheckboxField>
  );
}

Label rule

Always connect the visible label with the checkbox using htmlFor and id, unless the label wraps the control directly.

When to use CheckboxLink to section

Use Checkbox when options are independent and the user can select multiple choices.

Settings

Use for independent preferences, options, and account settings.

Filters

Use for multi-select filters where several values can apply at once.

Consent

Use for terms, confirmations, and explicit opt-in choices.

Checked stateLink to section

Use defaultChecked for uncontrolled checkboxes and checked with onCheckedChange for controlled product state.

This option starts checked and can be changed by the user.

This option starts unchecked.

checkbox-states.tsx
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

export function CheckboxStates() {
  return (
    <div className="grid gap-4">
      <CheckboxField>
        <Checkbox id="checked-example" defaultChecked />
        <CheckboxContent>
          <CheckboxLabel htmlFor="checked-example">
            Enabled by default
          </CheckboxLabel>
          <CheckboxDescription>
            This option starts checked and can be changed by the user.
          </CheckboxDescription>
        </CheckboxContent>
      </CheckboxField>

      <CheckboxField>
        <Checkbox id="unchecked-example" />
        <CheckboxContent>
          <CheckboxLabel htmlFor="unchecked-example">
            Optional setting
          </CheckboxLabel>
          <CheckboxDescription>
            This option starts unchecked.
          </CheckboxDescription>
        </CheckboxContent>
      </CheckboxField>
    </div>
  );
}

Controlled checkboxLink to section

Use a controlled Checkbox when the checked value drives application state.

Add auth, billing, and protected route foundations to the setup.

controlled-checkbox.tsx
"use client";

import * as React from "react";
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

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

  return (
    <CheckboxField>
      <Checkbox
        id="starter-pro"
        checked={checked}
        onCheckedChange={(value) => setChecked(value === true)}
      />
      <CheckboxContent>
        <CheckboxLabel htmlFor="starter-pro">
          Include Starter Pro wiring
        </CheckboxLabel>
        <CheckboxDescription>
          Add auth, billing, and protected route foundations to the setup.
        </CheckboxDescription>
      </CheckboxContent>
    </CheckboxField>
  );
}

State rule

Radix Checkbox can return true, false, or "indeterminate". Convert the value intentionally when your app expects a boolean.

Indeterminate stateLink to section

Use the indeterminate state for parent checkboxes when only some child items are selected.

Some features are currently selected.

indeterminate-checkbox.tsx
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

export function IndeterminateCheckbox() {
  return (
    <div className="grid gap-4">
      <CheckboxField>
        <Checkbox id="all-features" checked="indeterminate" />
        <CheckboxContent>
          <CheckboxLabel htmlFor="all-features">
            Select all features
          </CheckboxLabel>
          <CheckboxDescription>
            Some features are currently selected.
          </CheckboxDescription>
        </CheckboxContent>
      </CheckboxField>

      <div className="ml-7 grid gap-3 border-l border-border/60 pl-4">
        <CheckboxField>
          <Checkbox id="feature-auth" defaultChecked />
          <CheckboxLabel htmlFor="feature-auth">Authentication</CheckboxLabel>
        </CheckboxField>

        <CheckboxField>
          <Checkbox id="feature-billing" />
          <CheckboxLabel htmlFor="feature-billing">Billing</CheckboxLabel>
        </CheckboxField>

        <CheckboxField>
          <Checkbox id="feature-dashboard" defaultChecked />
          <CheckboxLabel htmlFor="feature-dashboard">Dashboard</CheckboxLabel>
        </CheckboxField>
      </div>
    </div>
  );
}

Disabled stateLink to section

Use disabled checkboxes only when the option cannot currently be changed.

This option is unavailable on the current plan.

This setting is enabled by default and cannot be changed.

disabled-checkbox.tsx
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

export function DisabledCheckbox() {
  return (
    <div className="grid gap-4">
      <CheckboxField>
        <Checkbox id="disabled-unchecked" disabled />
        <CheckboxContent>
          <CheckboxLabel htmlFor="disabled-unchecked">
            Enterprise-only option
          </CheckboxLabel>
          <CheckboxDescription>
            This option is unavailable on the current plan.
          </CheckboxDescription>
        </CheckboxContent>
      </CheckboxField>

      <CheckboxField>
        <Checkbox id="disabled-checked" defaultChecked disabled />
        <CheckboxContent>
          <CheckboxLabel htmlFor="disabled-checked">
            Required security baseline
          </CheckboxLabel>
          <CheckboxDescription>
            This setting is enabled by default and cannot be changed.
          </CheckboxDescription>
        </CheckboxContent>
      </CheckboxField>
    </div>
  );
}

Disabled copy

When a disabled option may frustrate users, explain why it is unavailable and what unlocks it.

Form validationLink to section

Use aria-invalid and supporting error copy when a required checkbox is not selected.

You must accept the terms before continuing.

checkbox-validation.tsx
import {
  Checkbox,
  CheckboxField,
  CheckboxContent,
  CheckboxLabel,
  CheckboxDescription,
} from "@pycolors/ui";

export function CheckboxValidation() {
  return (
    <CheckboxField>
      <Checkbox id="terms" aria-invalid="true" />
      <CheckboxContent>
        <CheckboxLabel htmlFor="terms">
          I agree to the terms
        </CheckboxLabel>
        <CheckboxDescription className="text-destructive">
          You must accept the terms before continuing.
        </CheckboxDescription>
      </CheckboxContent>
    </CheckboxField>
  );
}

Usage patternsLink to section

Use checkboxes for independent options

Each checkbox should represent one choice that can be selected without forcing a mutually exclusive decision.

Keep labels clear and specific

The label should explain exactly what gets enabled, selected, or confirmed.

Add descriptions for important consequences

Use CheckboxDescription when the choice affects privacy, billing, delivery, visibility, or access.

Handle indeterminate state intentionally

Use "indeterminate" only when representing a mixed group state.

Validate required confirmations

For required consent or terms fields, show a direct error message near the checkbox.

Checkbox vs Switch vs Radio GroupLink to section

SituationUse
Multiple independent selectionsCheckbox
Required consent or confirmationCheckbox
Parent selection with mixed childrenCheckbox with indeterminate state
Immediate on/off settingSwitch
One choice from a mutually exclusive groupRadio Group
Small menu action listDropdown Menu

Decision rule

Use Checkbox for selection, Switch for immediate enablement, and Radio Group for one exclusive choice.

APILink to section

Components

ComponentDescription
CheckboxRoot checkbox control built on Radix Checkbox
CheckboxFieldLayout helper for checkbox rows
CheckboxContentText stack helper for label and description
CheckboxLabelAccessible label helper
CheckboxDescriptionSupporting text helper

Checkbox props

PropTypeDefaultDescription
checkedboolean | "indeterminate"Controlled checked state
defaultCheckedboolean | "indeterminate"Initial uncontrolled checked state
onCheckedChange(checked) => voidCalled when the checked state changes
disabledbooleanfalseDisables the checkbox
requiredbooleanfalseMarks the checkbox as required
namestringForm field name
valuestringSubmitted form value
classNamestringAdditional Tailwind classes

Checkbox extends Radix Checkbox Root props.

TypeScript typesLink to section

checkbox-types.ts
export type CheckboxProps = React.ComponentPropsWithoutRef<
  typeof CheckboxPrimitive.Root
>;

const Checkbox = React.forwardRef<
  React.ComponentRef<typeof CheckboxPrimitive.Root>,
  CheckboxProps
>((props, ref) => {
  // ...
});

AccessibilityLink to section

Checkbox is built on Radix Checkbox primitives.

That means:

  • keyboard interaction is handled
  • checked and indeterminate states are exposed to assistive technologies
  • disabled state is exposed correctly
  • focus styling uses PyColors ring tokens
  • form usage works through native form semantics

Guidelines:

  • provide a visible label for every checkbox
  • connect labels using htmlFor and id
  • use descriptions for choices with consequences
  • do not rely on color alone for validation states
  • use aria-invalid for invalid required confirmations
  • keep checkbox labels short and action-oriented

Accessibility rule

A checkbox needs a clear accessible name. The label should make sense even when read without surrounding context.

Prefer / avoidLink to section

Prefer

  • clear labels connected with htmlFor and id
  • checkboxes for independent multi-select choices
  • descriptions for privacy, billing, or access impact
  • indeterminate state for mixed parent selection
  • visible validation copy for required confirmations

Avoid

  • using checkbox for mutually exclusive choices
  • using checkbox as an immediate setting when switch is clearer
  • labels that only say “Yes” or “Enable”
  • disabled options without explanation
  • color-only error communication

Product copy guidelinesLink to section

Checkbox copy should describe the selected outcome, not the UI control.

Send weekly product summary

Receive a short email with usage, billing, and workspace activity.

Show production-ready templates only

Hide mock-only examples from the template gallery.

Common questionsLink to section