Checkbox
Boolean selection control for settings, forms, filters, consent, and multi-select product flows in PyColors UI.
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
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.
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
Filters
Consent
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.
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.
"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.
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.
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.
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
| Situation | Use |
|---|---|
| Multiple independent selections | Checkbox |
| Required consent or confirmation | Checkbox |
| Parent selection with mixed children | Checkbox with indeterminate state |
| Immediate on/off setting | Switch |
| One choice from a mutually exclusive group | Radio Group |
| Small menu action list | Dropdown Menu |
Decision rule
Use Checkbox for selection, Switch for immediate enablement, and Radio Group for one exclusive choice.
APILink to section
Components
| Component | Description |
|---|---|
Checkbox | Root checkbox control built on Radix Checkbox |
CheckboxField | Layout helper for checkbox rows |
CheckboxContent | Text stack helper for label and description |
CheckboxLabel | Accessible label helper |
CheckboxDescription | Supporting text helper |
Checkbox props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | "indeterminate" | — | Controlled checked state |
defaultChecked | boolean | "indeterminate" | — | Initial uncontrolled checked state |
onCheckedChange | (checked) => void | — | Called when the checked state changes |
disabled | boolean | false | Disables the checkbox |
required | boolean | false | Marks the checkbox as required |
name | string | — | Form field name |
value | string | — | Submitted form value |
className | string | — | Additional Tailwind classes |
Checkbox extends Radix Checkbox Root props.
TypeScript typesLink to section
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
htmlForandid - use descriptions for choices with consequences
- do not rely on color alone for validation states
- use
aria-invalidfor 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.
I agree to receive delivery emails
Required to send product access, download links, and order recovery messages.