Checkbox
A tri-state checkbox — checked, unchecked, or indeterminate — built on a real <input type="checkbox"> rather than a hidden input paired with a fake visual.
Usage#
import { Checkbox } from "neelam-ui";
<label className="flex items-center gap-2.5">
<Checkbox defaultChecked />
Email me about product updates
</label>Labelling#
There is no CheckboxLabel. An ordinary <label> wrapping the checkbox and its
text already associates the two natively, and gives you the click target for
free — a bundled component would only wrap what the platform does correctly.
A checkbox with no label has no name
If the design has no visible text — a checkbox in a table header, say — pass
aria-label. A screen reader otherwise announces only "checkbox".
Indeterminate#
Pass checked="indeterminate" for a parent whose children disagree. This is the
"select all" case: the box is neither on nor off, and the mixed state says so
rather than guessing.
indeterminate is a DOM property, not an HTML attribute — <input> accepts no
such React prop, so it can only be set imperatively. Checkbox does that for
you in an effect; from the outside it is just another value of checked.
Indeterminate is a display state, not a value
A form submits an indeterminate checkbox as unchecked, exactly as the platform does. It communicates "partially selected" to the user; it is not a third value you can read back.
Controlled#
checked and onCheckedChange drive the checkbox from your own state. Omit
both and it manages itself, the same as a plain <input>:
const [checked, setChecked] = useState(false);
<Checkbox checked={checked} onCheckedChange={setChecked} />onCheckedChange receives a plain boolean. The underlying onChange still
fires with the native event if you need it.
Keyboard#
| Key | Behaviour |
|---|---|
| Tab | Moves focus to the checkbox. Disabled checkboxes are skipped. |
| Space | Toggles the checkbox — native behaviour, not re-implemented. |
Accessibility#
- Renders a native
<input type="checkbox">, so the role, the checked state,Spaceactivation, and participation in a<form>'s submitted data all come from the browser. - The overlaid check and dash icons are
aria-hidden. State is already carried by the input's owncheckedandindeterminateproperties, so announcing the glyph too would be a duplicate. - Styling uses
appearance-nonewith thechecked:andindeterminate:variants on the real input, so focus and hit target stay on the element assistive tech is actually reporting.
API reference#
| Prop | Type | Default |
|---|---|---|
checked`true`, `false`, or `"indeterminate"` for a partially-checked state (e.g. a "select all" checkbox over a mixed selection). Omit to let the checkbox manage its own state, same as a plain `<input>`. | CheckedState | — |
defaultChecked | boolean | — |
onCheckedChange | ((checked: boolean) => void) | — |
Also accepts every native <input> attribute except type and the tri-state
checked — name, value, required, disabled, aria-*, and the rest.