Checkbox
A binary selection control with three visual states (unchecked / checked / indeterminate) and three interaction states (default / hover / disabled). Built on a native <input type="checkbox"> — fully keyboard-accessible with no JS required for state.
When to use
- Use for multi-select — when the user can pick zero or more options from a list
- Use for binary settings that take effect only after a Save or Submit action
- Use the indeterminate state for a "select all" parent that has mixed children
- Always pair with a visible label that describes what checking the box does
- Group related checkboxes together with a clear group heading
- Use when only one option can be selected — use Radio Button instead
- Use for a setting that takes effect immediately — use Toggle Switch instead
- Use without a label — a bare checkbox with no description is inaccessible
- Use more than 8 checkboxes in a flat list — consider grouping or a Dropdown
- Use to trigger an action directly — use a Button
DigiLawyer Patterns
Product-specific conventions used across DigiLawyer interfaces.
Anatomy
A Checkbox is composed of a hidden native input, a visible box, and an optional label. The box and glyph are CSS-only — no SVG injection at runtime.
- 1Hidden input —
.checkbox-input. Visually hidden but focusable. Drives all states via CSS:checked,:disabled,:focus-visibleusing the~sibling selector. - 2Box —
.checkbox-box. The visible square. Background and border change per state via sibling CSS. - 3Check glyph — Rendered inside
.checkbox-box::afterusing the#ico-checkSVG symbol from the ds.js sprite when checked. - 4Dash glyph — Rendered via
#ico-dashsprite symbol for the indeterminate state. - 5Label —
.checkbox-label. Always placed to the right of the box. Required for accessibility.
Default
Wrap a native input + a styled box in a <label class="checkbox">. The input is visually hidden but stays in the focus path; the .checkbox-box renders the visible square and shows the right glyph based on :checked / :indeterminate.
<label class="checkbox"> <input type="checkbox" class="checkbox-input"> <span class="checkbox-box"> <svg class="checkbox-check"><use href="#ico-check"/></svg> <svg class="checkbox-dash"><use href="#ico-dash"/></svg> </span> <span class="checkbox-label">I agree to the terms</span> </label>
Variants
Three visual states. Unchecked and Checked map to the input's native boolean. Indeterminate is a third visual state used for parent rows in tree / list selection — it can't be set via an HTML attribute, only via input.indeterminate = true in JS.
// Indeterminate is a JS-only property — set it after the input mounts. document.querySelectorAll('[data-indeterminate]').forEach(el => { el.indeterminate = true; });
States
Three interaction states. Hover and focus are CSS-driven (real interaction required to see them — or use the .is-hover doc helper to force the visual). Disabled uses the HTML disabled attribute on the input.
Full matrix
3 variants × 3 states, mirroring the Figma source. Default row is interactive; Hover row uses the .is-hover documentation helper to force the hover visual at rest; Disabled row uses the native disabled attribute.
Accessibility
Built on a native <input type="checkbox"> — all ARIA semantics are implicit. No additional role attributes needed.
| Attribute / Behaviour | Value | Notes |
|---|---|---|
| Role | checkbox | Implicit from native <input type="checkbox"> |
| Keyboard — toggle | Space | Checks or unchecks a focused checkbox |
| Keyboard — focus | Tab / Shift+Tab | Moves focus between checkboxes and other interactive elements |
aria-checked="mixed" | Indeterminate state | Set via JS: input.indeterminate = true. CSS alone cannot set this state. |
disabled | HTML boolean | Removes from tab order and blocks interaction |
| Label association | <label> wrapping | Always wrap input + label in a <label> element. Never use aria-label as a substitute for a visible label. |
| Group heading | <fieldset> + <legend> | Use to give a group of related checkboxes a shared accessible name |
API
| Class / attr | On | Description |
|---|---|---|
| .checkbox | <label> | Wrapper. Makes the whole row a click/tap target for the input inside. |
| .checkbox-input | <input type="checkbox"> | The native input, visually hidden but accessible and focusable. Drives the visual via :checked / :indeterminate / :disabled. |
| .checkbox-box | <span> | The visible 16×16 square with border and fill. Contains the two glyph SVGs. |
| .checkbox-check | <svg> | Glyph shown when the input is :checked. Uses sprite symbol #ico-check. |
| .checkbox-dash | <svg> | Glyph shown when the input is :indeterminate. Uses sprite symbol #ico-dash. |
| .checkbox-label | <span> | The text label. Inherits muted color + reduced opacity when the input is disabled. |
| checked | <input> | HTML attribute — checkbox starts checked. |
| disabled | <input> | HTML attribute — disables interaction; styling swaps to --checkbox-bg-disabled / --checkbox-checked-bg-disabled. |
| input.indeterminate | JS property | Sets the indeterminate visual. Not expressible as an HTML attribute — assign via JS after mount. |
| .is-hover | .checkbox | Documentation helper — forces the hover visual at rest. Used in the Full matrix; not needed in production. |