Skip to main content

Checkbox

A checkbox is Headless UI's Checkbox (a <span role="checkbox"> with a hidden input for form submission) drawn as an icon-sized box. With label or description it wraps itself in a Headless UI Field, so clicking the label toggles it and the description lands in aria-describedby.

import Checkbox from '@zuilib/primitives/checkbox'

Basic

checked + onCheckedChange for controlled, defaultChecked for uncontrolled. onCheckedChange receives the boolean, not an event.

Loading example

Sizes and label position

The box is size-4/5/6 (the shared icon scale, so it matches option check marks and chevrons); the text beside it is text-sm for sm and md, text-base for lg. labelPosition="start" puts the text first.

Loading example

Indeterminate

indeterminate shows the mixed state (aria-checked="mixed", data-indeterminate) for a parent whose children are partly selected.

Loading example

In a Field

Without label / description only the box renders, so it picks up the enclosing Field's Label, FieldDescription and FieldError. invalid defaults to the field's invalid, and disabled (left undefined) inherits from the Field / Fieldset.

Loading example

Props

CheckboxProps extends Headless UI CheckboxProps (minus as, children) with:

PropTypeDefaultDescription
checkedbooleanControlled state; use defaultChecked for uncontrolled
defaultCheckedbooleanfalse
onCheckedChange(checked: boolean) => void
indeterminatebooleanfalsearia-checked="mixed", data-indeterminate, a dash instead of a check
labelReactNodeVisible label; wraps the control in a Field so clicking it toggles
descriptionReactNodeHelper text wired through aria-describedby
labelPosition'end' | 'start''end'Where the label and description sit relative to the box
size'sm' | 'md' | 'lg''md'
invalidbooleanField invalidaria-invalid, data-invalid, danger border and ring
disabledbooleanField / Fieldset disabledLeave unset to inherit; an explicit false overrides the context
namestringNative form participation via a hidden input
valuestring'on'Submitted value when checked
classNamestringMerged last onto the box (the element ref points at)

Slots

SlotElementNotes
[data-slot="checkbox"]spanThe box. Headless UI sets data-checked, data-indeterminate, data-hover, data-focus, data-disabled; ZUI adds data-invalid
[data-slot="checkbox-indicator"]svgCheck / dash glyph; aria-hidden, fades in when checked or indeterminate
[data-slot="checkbox-field"]divPresent with label / description: the Headless UI Field
[data-slot="checkbox-text"]divColumn holding label and description
[data-slot="checkbox-label"]label
[data-slot="checkbox-description"]p
/* Consumer CSS: a circular checkbox for a brand that uses round toggles */
[data-slot="checkbox"] {
border-radius: var(--radius-full);
}

Accessibility

  • The box has role="checkbox" and aria-checked (true, false or mixed); a hidden input carries name / value to the form.
  • Space toggles the value; Tab moves through boxes in document order.
  • With label the <label> is associated to the box through the Field, so clicking the label toggles it. Pass the same id on the control when you set one; the label's htmlFor follows it.
  • description and a Field's FieldDescription / FieldError are joined into aria-describedby.
  • invalid sets aria-invalid, paints the border --danger and turns the keyboard ring the danger colour. Keyboard focus shows the shared --ring ring (focus-visible only).
  • disabled sets data-disabled and aria-disabled on the box and dims the label.