|Kit

Checkbox

A single boolean (or tri-state) control on Ark UI's Checkbox machine — inline label, built-in description / error, native form submission, and full keyboard / ARIA.

Checkbox is a single boolean control with an inline label. The box reuses the family's shared control surface, so it sits flush beside an Input, and description / error / required are built in via Field. It implements the kit's form-control contract — name submits, and ref / onBlur land on the hidden input — so it binds to react-hook-form, TanStack Form, or a plain <form> with no glue.

import { Checkbox } from '@42-central/ui-react/checkbox';

<Checkbox label="Follow the Norm" />

Playground

Component

Loading preview

Props

Code

<Component
  label="Follow the Norm"
  size="md"
  variant="default"
/>

Sizes

Five sizes — xs through xl — matching the rest of the family. The box and its mark scale together.

Code

<Checkbox size="xs" label="xs" defaultChecked />
<Checkbox size="sm" label="sm" defaultChecked />
<Checkbox size="md" label="md" defaultChecked />
<Checkbox size="lg" label="lg" defaultChecked />
<Checkbox size="xl" label="xl" defaultChecked />

Variants

Two variants decide the checked fill. default is a neutral, monochrome box that stays palette-independent; filled tints the checked fill with color.

Code

<Checkbox variant="default" label="Default" defaultChecked />
<Checkbox variant="filled" color="brand" label="Filled" defaultChecked />

Colors

color tints the checked box in the filled variant — the default variant stays monochrome. The resting box is palette-independent, and the focus ring is always the brand ring. Set data-color once on the root and every kit palette tints for free.

Code

<Checkbox variant="filled" color="brand" label="brand" defaultChecked />
<Checkbox variant="filled" color="green" label="green" defaultChecked />
<Checkbox variant="filled" color="blue" label="blue" defaultChecked />
<Checkbox variant="filled" color="purple" label="purple" defaultChecked />
<Checkbox variant="filled" color="red" label="red" defaultChecked />

Disabled & indeterminate

disabled dims the control and blocks interaction. The tri-state checked="indeterminate" renders a partial (minus) mark — drive it from the parent, e.g. a "select all" header whose children are partly checked. It never sets itself.

Code

<Checkbox label="Disabled" disabled />
<Checkbox label="Disabled, checked" disabled defaultChecked />
<Checkbox label="Select all projects" checked="indeterminate" />

With description & error

description (helper text) and error sit below the control via the built-in Field. Passing error flips the box to the invalid (red) state; required adds the semantic flag and a red asterisk on the label.

Code

<Checkbox
  label="Evaluation reminders"
  description="We'll only ping you about peer evaluations."
  defaultChecked
/>

<Checkbox label="I accept the Code of Conduct" required />

<Checkbox label="I accept the Code of Conduct" error="You must accept to continue" />

Controlled

Drive the checked state from state. onCheckedChange hands you the next value — boolean, or "indeterminate" if you've set that.

'use client';
import { useState } from 'react';
import { Checkbox } from '@42-central/ui-react/checkbox';

export function TermsCheckbox() {
  const [checked, setChecked] = useState(false);
  return (
    <Checkbox
      label="Follow the Norm"
      checked={checked}
      onCheckedChange={(next) => setChecked(next === true)}
    />
  );
}

Forms

Checkbox renders a hidden native <input type="checkbox">, so a name wires it into native <form> submission and FormData. The submitted value defaults to "on".

<form action={save}>
  <Checkbox name="events" value="yes" label="Subscribe to 42 events" />
</form>

API

Prop

Type

Accessibility

  • Full Checkbox model from Ark: Space toggles, focus shows the ring, and the box / label / description / error associations are wired (the latter via the built-in Field).
  • A hidden native <input type="checkbox"> backs form submission and exposes role="checkbox" with aria-checked (incl. "mixed" for the indeterminate state).
  • invalid (or error) sets aria-invalid on the input.
  • testId renders as data-testid on that same root element, never the hidden native input. See the Testing guide.
  • RTL is honored via the document dir — the box and label mirror automatically.

Changelog

v0.17.0
  • Keep the visually hidden input contained inside the control

    #265
v0.11.0
  • The focus ring narrows from 3px to 2px, matching the rest of the kit

    #161
v0.6.0
  • The description sits above the control, and the error shows independently of it

    #101
v0.0.1
  • Checkbox, RadioGroup and Switch

On this page