Checkbox

Labelled checkbox with a full-height 44px click row.

atomsSource
import { Checkbox } from '@elirobinson/react/components/atoms/Checkbox';

Styles: @elirobinson/react/styles/atoms/Checkbox.css — already included when you import @elirobinson/react/styles.css.

Show code
import { Checkbox } from '@elirobinson/react/components/atoms/Checkbox';

export default function Basic() {
  return <Checkbox label="Email me weekly coaching tips" />;
}

When to use it

Reach for Checkbox when the choice is independent and part of a form that gets submitted — pick any number of options, in any combination. Reach for Switch instead when flipping it takes effect immediately, with no submit step (a notification preference, a feature flag). Reach for RadioGroup when only one of several options can be true at once.

States

Show code
import { Checkbox } from '@elirobinson/react/components/atoms/Checkbox';

export default function States() {
  return (
    <div className="demo-col">
      <Checkbox label="Unchecked" />
      <Checkbox label="Checked by default" defaultChecked />
      <Checkbox label="Disabled" disabled />
      <Checkbox label="Disabled and checked" disabled defaultChecked />
    </div>
  );
}

Controlled

Checkbox forwards every native input prop, so checked and onChange work exactly like a plain <input type="checkbox">.

1 of 4 modules in this session.

Show code
import { useState } from 'react';

import { Checkbox } from '@elirobinson/react/components/atoms/Checkbox';

const MODULES = ['Warm-up drills', 'Passing circuit', 'Small-sided game', 'Cooldown stretch'];

export default function Controlled() {
  const [selected, setSelected] = useState<string[]>(['Warm-up drills']);

  const toggle = (module: string) => {
    setSelected((current) =>
      current.includes(module) ? current.filter((item) => item !== module) : [...current, module],
    );
  };

  return (
    <div className="demo-col">
      {MODULES.map((module) => (
        <Checkbox
          key={module}
          label={module}
          checked={selected.includes(module)}
          onChange={() => toggle(module)}
        />
      ))}
      <p>
        {selected.length} of {MODULES.length} modules in this session.
      </p>
    </div>
  );
}

Props

PropTypeDefaultDescription
labelrequiredstring

Also accepts all Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> props.

Accessibility

  • Renders a native <input type="checkbox"> paired with a <label>label is required and is the input's only accessible name.
  • The id is auto-generated with useId when you don't pass one, so htmlFor always resolves.
  • Keyboard: Tab focuses, Space toggles — native input behavior, nothing reimplemented.
  • The row reserves a 44px minimum height for rhythm alongside other controls, but the actual hit target is the 18×18 box and the label text — clicking the empty vertical space around them doesn't toggle it.
  • The ref forwards to the underlying <input>.

Do

  • Use Checkbox for independent yes/no choices inside a form that submits together.
  • Always pass a real, specific label — it’s required, and it’s the input’s only accessible name.
  • Group related checkboxes visually (a card, a list) so “N selected” context is clear.
  • Let defaultChecked or checked drive pre-selected state — don’t manage a shadow copy elsewhere.

Don't

  • Use Checkbox when only one answer can be true — that’s RadioGroup.
  • Use Checkbox for a setting that takes effect the instant it’s flipped — that’s Switch.
  • Expect the full 44px row to be clickable — only the box and the label text respond.
  • Omit the label prop and lean on placeholder or nearby text — there’s no other accessible name path.