Checkbox
A fully accessible checkbox component supporting checked, unchecked, and indeterminate states. It can be used in both controlled and uncontrolled modes and follows native checkbox behavior with custom styling.
Usage
Basic usage (controlled)
import { Checkbox } from '@nofinite/nui';
import React from 'react';
const Example = () => {
const [checked, setChecked] = React.useState(false);
return (
<Checkbox
label="I agree to the Terms"
checked={checked}
onChange={setChecked}
/>
);
};
Uncontrolled usage
<Checkbox label="Subscribe to newsletter" defaultChecked />
Variants
The Checkbox does not expose visual variants via props.
Visual states are driven by its internal state handling.
<Checkbox />
<Checkbox checked />
<Checkbox indeterminate />
Visual states:
unchecked– empty boxchecked– checkmarkindeterminate– dash
Guidelines:
- Use
indeterminatefor partial selections (for example, a parent checkbox in a list). - Do not mix
checkedandindeterminatelogic ambiguously in user experience flows.
Sizes
This component renders at a fixed size (16px × 16px) as defined in CSS.
If size variations are required, they should be implemented via:
- CSS overrides
- Wrapper scaling
- Future size props (if introduced)
States
Disabled
<Checkbox label="Disabled option" disabled />
Behavior:
- Click interaction is blocked.
- Cursor and visual feedback indicate a non-interactive state.
- State cannot be toggled.
Indeterminate
<Checkbox indeterminate label="Partially selected" />
Behavior:
- Visual-only state implemented using
HTMLInputElement.indeterminate. - Does not automatically toggle between checked and unchecked.
- Intended to be controlled by parent logic.
Native Props / Composition
Checkbox is built on a native <input type="checkbox"> and forwards relevant attributes:
<Checkbox
name="terms"
value="accepted"
onChange={handleChange}
aria-label="Accept terms"
/>
Custom class names can also be provided:
<Checkbox className="my-custom-checkbox" label="Custom styled" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled checked state |
defaultChecked | boolean | false | Initial value for uncontrolled usage |
indeterminate | boolean | false | Enables indeterminate visual state |
onChange | (checked: boolean) => void | — | Called when checkbox toggles |
label | React.ReactNode | — | Label content rendered next to checkbox |
disabled | boolean | false | Disables interaction |
name | string | — | Native input name |
value | string | — | Native input value |
className | string | "" | Additional CSS classes |
Behavior Notes
- Supports controlled (
checked) and uncontrolled (defaultChecked) usage. indeterminateis applied imperatively via a ref to the input element.- User interaction toggles only between checked and unchecked.
- In controlled mode, internal state is ignored.
Example:
<Checkbox checked={state} indeterminate={!allSelected} onChange={setState} />
Accessibility
-
Renders as a native
<input type="checkbox">. -
Fully keyboard accessible:
Tabto focusSpaceto toggle
-
Uses visible focus styles via
:focus-visible. -
Label is clickable when provided through the
<label>wrapper. -
For label-less usage, an accessible name must be provided via
aria-label.
Example:
<Checkbox aria-label="Select item" />
Layout
- Inline-flex layout by default.
- Checkbox and label are horizontally aligned.
- Does not stretch to full width unless wrapped.
<div style={{ width: '100%' }}>
<Checkbox label="Full-width container example" />
</div>
Best Practices
Do
- Use
indeterminatefor partial or grouped selections. - Prefer controlled mode when integrating with form or application state.
- Provide clear and descriptive labels.
Don’t
- Use
indeterminateas a final selection state. - Mix controlled and uncontrolled props.
- Rely on color alone to communicate state.