Tessera UI

Checkbox

A form control that lets users select one or more options. Supports checked, unchecked, and indeterminate states. Five sizes, five intents, label/description/error patterns, and a CheckboxGroup compound component with select-all support.

Installation

pnpm add @tessinaui/ui

Usage

import { Checkbox, CheckboxGroup } from "@tessinaui/ui";
{/* Standalone */}
<Checkbox label="Accept terms and conditions" />

{/* Controlled */}
<Checkbox
  checked={accepted}
  onCheckedChange={(val) => setAccepted(val as boolean)}
  label="Accept terms"
/>

{/* With description and error */}
<Checkbox
  label="Accept terms"
  required
  intent="error"
  errorMessage="You must accept the terms to continue."
/>

{/* Group with select-all */}
<CheckboxGroup
  value={selected}
  onValueChange={setSelected}
  allValues={["a", "b", "c"]}
  label="Choose options"
>
  <Checkbox name="a" value="a" label="Option A" />
  <Checkbox name="b" value="b" label="Option B" />
  <Checkbox name="c" value="c" label="Option C" />
</CheckboxGroup>

Playground

Preview
Loading...

Contact List Example

A common pattern combining Checkbox with Avatar for selecting contacts or friends.

Preview
Loading...

Showcase

Preview
Loading...

API Reference

Checkbox props

PropTypeDefaultDescription
variant"filled" | "outline""filled"Unchecked style: filled has bg-secondary, outline is transparent
size"xs" | "sm" | "md" | "lg" | "xl""md"Visual size of the checkbox box
intent"none" | "error" | "warning" | "success" | "info""none"Semantic color for border / fill
checkedbooleanControlled checked state
defaultCheckedbooleanfalseUncontrolled initial state
onCheckedChange(checked: boolean) => voidChange handler
indeterminatebooleanfalseMixed state (renders Minus icon)
disabledbooleanfalsePrevents interaction
readOnlybooleanfalsePrevents interaction, accessible
requiredbooleanfalseHTML required + asterisk on label
labelstringText label rendered beside the checkbox
descriptionstringHelper text below the label
errorMessagestringError text (overrides description, adds AlertCircle)
labelPosition"left" | "right""right"Which side the label appears on
dir"ltr" | "rtl"Text direction for the wrapper
namestringInput name for form submission
valuestringValue submitted with the form
parentbooleanMarks as select-all within a CheckboxGroup
classNamestringExtra classes on the wrapper <div>

All other native attributes are forwarded to the underlying <span> (Base UI).

CheckboxGroup props

PropTypeDefaultDescription
valuestring[]Controlled list of checked values
defaultValuestring[][]Uncontrolled initial values
onValueChange(value: string[]) => voidChange handler
allValuesstring[]All possible values — enables select-all indeterminate logic
disabledbooleanfalseDisables all checkboxes in the group
orientation"vertical" | "horizontal""vertical"Stack direction
variant"filled" | "outline""filled"Propagated to child Checkboxes
sizeCheckboxSize"md"Propagated to child Checkboxes
intentCheckboxIntent"none"Propagated to child Checkboxes
labelstringGroup legend
descriptionstringHelper text below legend
errorMessagestringError text for the group
requiredbooleanfalseAsterisk on group legend
dir"ltr" | "rtl"Text direction for the group wrapper

States

StateVisual
UncheckedEmpty box with border
CheckedFilled box + Check icon (white)
IndeterminateFilled box + Minus icon (white)
Disabled uncheckedMuted empty box
Disabled checkedMuted filled box + muted icon
FocusRing outline (2px)
Hover (unchecked)Darker border
Hover (checked)Slightly darker fill

Sizes

SizeBoxRoundedText size
xs14×14 pxrounded-smtext-xs
sm16×16 pxroundedtext-sm
md20×20 pxrounded-mdtext-sm
lg24×24 pxrounded-mdtext-base
xl28×28 pxrounded-lgtext-base

Intents

IntentUnchecked borderChecked fill
noneborder-borderbg-primary
errorborder-errorbg-error
warningborder-warningbg-warning
successborder-successbg-success
infoborder-infobg-info

Checkbox Group patterns

Uncontrolled

<CheckboxGroup defaultValue={["email"]} label="Notifications">
  <Checkbox name="email"  value="email"  label="Email" />
  <Checkbox name="sms"    value="sms"    label="SMS" />
  <Checkbox name="push"   value="push"   label="Push" />
</CheckboxGroup>

Select all (parent)

const all = ["a", "b", "c"];
const [selected, setSelected] = useState<string[]>([]);

<CheckboxGroup value={selected} onValueChange={setSelected} allValues={all}>
  <Checkbox
    name="all"
    parent
    label="Select all"
    checked={selected.length === all.length}
    indeterminate={selected.length > 0 && selected.length < all.length}
    onCheckedChange={(checked) => setSelected(checked ? [...all] : [])}
  />
  {all.map((v) => (
    <Checkbox key={v} name={v} value={v} label={v} />
  ))}
</CheckboxGroup>

Horizontal

<CheckboxGroup orientation="horizontal" label="Days">
  <Checkbox value="mon" label="Mon" />
  <Checkbox value="tue" label="Tue" />
  <Checkbox value="wed" label="Wed" />
</CheckboxGroup>

Accessibility

  • Hidden <input type="checkbox"> rendered by Base UI — native form semantics
  • aria-checked="mixed" set automatically for indeterminate state
  • aria-invalid set on checkbox + group when errorMessage is present
  • aria-describedby links error messages to their respective controls
  • Required: aria-required + native required attribute on hidden input
  • Focus ring visible at all sizes — complies with WCAG 2.1 AA (3:1 contrast)
  • Touch target: minimum 44×44 px achieved via padding on the wrapper
  • Group rendered as <fieldset> + <legend> for screen reader context

On this page