Skip to main content

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 box
  • checked – checkmark
  • indeterminate – dash

Guidelines:

  • Use indeterminate for partial selections (for example, a parent checkbox in a list).
  • Do not mix checked and indeterminate logic 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

PropTypeDefaultDescription
checkedbooleanControlled checked state
defaultCheckedbooleanfalseInitial value for uncontrolled usage
indeterminatebooleanfalseEnables indeterminate visual state
onChange(checked: boolean) => voidCalled when checkbox toggles
labelReact.ReactNodeLabel content rendered next to checkbox
disabledbooleanfalseDisables interaction
namestringNative input name
valuestringNative input value
classNamestring""Additional CSS classes

Behavior Notes

  • Supports controlled (checked) and uncontrolled (defaultChecked) usage.
  • indeterminate is 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:

    • Tab to focus
    • Space to 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 indeterminate for partial or grouped selections.
  • Prefer controlled mode when integrating with form or application state.
  • Provide clear and descriptive labels.

Don’t

  • Use indeterminate as a final selection state.
  • Mix controlled and uncontrolled props.
  • Rely on color alone to communicate state.