Description
Checkbox lets a user toggle a binary choice: selected or not selected. In a group, multiple checkboxes can be selected simultaneously.
Multi-select option lists, filter panels, permission settings, and any context where users need to pick one or more items from a set.
When multiple selections are valid, checkboxes are the appropriate control — they make it visually clear that combinations are permitted. Radio buttons do not allow this.
A single checkbox is appropriate for a single binary decision: "I agree to the terms". A group of checkboxes is appropriate for multi-select lists. Standalone checkboxes should never need a fieldset.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Checkbox control | Required | The interactive square. Must be 16–20px for touch usability, with a minimum 44×44px hit area. |
| Checked indicator | Conditional | Checkmark shown when selected. A dash (—) indicates an indeterminate state in parent/child group patterns. |
| Label | Required | Plain language description of the option. Always visible — never use placeholder text as a label. |
| Group container | Conditional | A <fieldset> wrapping all related checkboxes. Required for groups; omit for standalone checkboxes. |
| Group label | Conditional | A <legend> describing what the group of checkboxes collectively represents. Required when using a fieldset. |
States
| State | Behaviour |
|---|---|
| Unchecked | Empty box. Default state. |
| Checked | Box with checkmark. Option is selected. |
| Indeterminate | Box with dash. Used in parent/child tree patterns when some — but not all — child items are checked. Not a user-selectable state; set via JavaScript. |
| Disabled | Greyed out. Use only when a checkbox is unavailable for a specific, communicated reason. Disabled fields are not announced to screen readers — consider using a read-only alternative. |
| Focus | Focus ring on control. 2px solid focus ring, --op-color-focus-ring, with 2px offset. |
| Error | Red border + error message. Used when a required group has no selection. See Form Control documentation. |
Usage guidelines
Checkbox vs Radio Button vs Switch
| Control | Use when |
|---|---|
| Checkbox | Multiple selections are valid. "Which notification types do you want?" |
| Radio button | Exactly one selection is required. "How often should this reminder fire?" |
| Switch | A single setting is being toggled on or off with immediate effect. |
Do / Don't
Do
Use positive language for checkbox labels. "Email me about new responses" is clearer than "Don't suppress email notifications".
Don't
Don't use a checkbox to trigger an immediate action. Checkboxes are form inputs — their effect applies on form submission, not on click. Use a Switch for immediate-effect toggles.
Do
Use <fieldset> + <legend> for all checkbox groups. This is what makes the group label accessible — CSS styling alone doesn't communicate group structure to screen readers.
Don't
Don't use checkboxes for a single required choice where exactly one option must be selected. That's a radio button.
Layout & Spacing
| Element | Spec |
|---|---|
| Control size | 18×18px |
| Hit area | 44×44px minimum (extend via padding) |
| Border radius | --op-radius-sm (3px) |
| Gap (control to label) | --op-space-8 |
| Gap (between items in group) | --op-space-12 |
| Label font size | --op-text-sm |
| State | Control background | Border |
|---|---|---|
| Unchecked | --op-color-bg-primary |
--op-color-border-strong |
| Checked | --op-color-interactive-default |
--op-color-interactive-default |
| Indeterminate | --op-color-interactive-default |
--op-color-interactive-default |
| Disabled | --op-color-bg-disabled |
--op-color-border-default |
| Error | --op-color-bg-primary |
--op-color-status-error |
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Moves focus to the checkbox (or the next checkbox in a group). |
| Space | Toggles the checkbox state. |
Why it matters
Checkbox groups are one of the most commonly mislabelled form patterns. When multiple checkboxes share a visual heading but aren't wrapped in a <fieldset>, a screen reader user hears each option in isolation — without knowing what question is being answered. The fieldset/legend combination is what connects the options to their group context.
Required ARIA and HTML
| Pattern | Requirement |
|---|---|
| Standalone checkbox | Always use <label> wrapping the input and its visible text. Never use placeholder text as a label. |
| Checkbox group | Wrap in <fieldset> with a <legend> that describes the group. Don't use a <div> with ARIA substitutes — the native elements are more reliable. |
| Required group | The error message must be connected to the fieldset via aria-describedby. Don't rely on visual proximity alone. |
| Indeterminate | The indeterminate property is JavaScript-only. It has no HTML attribute equivalent. Announce the state change programmatically if needed: aria-label="Select all (partially selected)". |
Things to avoid
- Don't style a
<div>or<span>to look like a checkbox. Native<input type="checkbox">provides keyboard, focus, and announcement behaviour for free. - Don't use custom checkboxes without
role="checkbox",aria-checked, and full keyboard support if native inputs are unavailable. - Don't disable checkboxes that users might expect to interact with. If a checkbox is unavailable because of a condition, explain the condition nearby.