Checkbox

Checkbox

View in Storybook

A Checkbox lets users toggle a boolean state on or off. It pairs a visually hidden native <input type="checkbox"> with a custom styled box, giving full keyboard and form support while keeping the Win95 bevel aesthetic.


Overview


When to use

  • To let users toggle a single boolean option (paid / unpaid, enabled / disabled).
  • Inside a list to mark individual items.
  • In forms where an option can be independently on or off.

When not to use

  • To select one option from a group — use a radio button instead.
  • As a trigger for an immediate action — use a Button.

States

Unchecked
Checked
Disabled unchecked
Disabled checked

Unchecked — default state, empty box with sunken bevel.

Checked — white background with pixel-art checkmark rendered inside.

Disabled unchecked — gray background (--color-accent-primary) with not-allowed cursor.

Disabled checked — gray background with muted checkmark color.


Accessibility

The component uses a native <input type="checkbox"> (visually hidden, positioned over the visual box) to handle:

  • Keyboard: Space bar toggles; Tab moves focus naturally.
  • Screen readers: The element is announced as a checkbox with its current state.
  • Focus ring: Visible outline on keyboard focus via focus-visible.

Always associate a visible label using id + <label htmlFor>:

<Checkbox id="paid" checked={isPaid} onCheckedChange={setIsPaid} />
<label htmlFor="paid">Mark as paid</label>

Usage inside a label

The recommended pattern for toggling a row or list item is to wrap the checkbox and its associated content in a <label>. Clicking anywhere on the label — including the text — toggles the checkbox:

<label htmlFor="paid" style={{ display: 'flex', gap: '8px', cursor: 'pointer' }}>
<Checkbox id="paid" checked={isPaid} onCheckedChange={setIsPaid} />
Bill name
</label>

Controls

Interactive controls are available in Storybook. Open Storybook


Props


Token mapping

PropertyToken
background (unchecked)--color-bg-page
background (checked)--color-bg-page
background (disabled)--color-accent-primary
checkmark color--primitive-black
checkmark color (disabled)--color-text-muted
bevel (top-left outer)--sunken-outer-dark
bevel (bottom-right outer)--sunken-outer-light
bevel (top-left inner)--sunken-inner-dark
bevel (bottom-right inner)--sunken-inner-light

Changelog

DateChange
2026-03-23Migrated to Tailwind; replaced div+role with native input for keyboard/form support; API updated to onCheckedChange; added disabled state; checkmark uses currentColor; added index.ts, stories, and documentation
2026-03-15Initial component created