Design system/Components
Checkbox
A checkbox turns an independent choice on or off in a form that gets submitted later. The box is 20px, but the whole labeled row, at least 44px, is the tap target.
In codecomponents/controls.tsx (Checkbox)components/controls.css
Live example
Try every state. Tapping the label checks it too; Tab to it and press Space to see the focus ring.
States
20 × 20px · r 6px · border 1.5pxborder var(--border-strong) · bg var(--card)border var(--text-tertiary)scale(0.9) · 0.12sbg var(--accent) · glyph #fff 14px / 2.6outline 2px var(--accent) · offset 2pxopacity 0.45 · cursor not-allowedborder var(--red)min-height 44px · gap 10px · padding-block 12px13.5px / 600 · 11.5px / 400padding 12px 14px · r 12pxOn: orange border at 45 percentAnatomy
- Touch areaA native, invisible input, 12px bigger than the box on each side; click, keyboard, and form all go through that input.
- Box20px, on the first line of the label, at the start of the row in both directions.
- TagWhat checking it does, as a positive sentence.
- AboutOptional; the consequence of the choice in one quiet line.
When
When to use it
- One independent choice in a form: “Group meeting”, “Create an autopay action”.
- Several independent choices from a list: which suggested actions to create.
- The parent of a list where some children are selected: the mixed (indeterminate) state.
When not to
- A setting that applies immediately without a save button: a switch.
- Several options where only one is valid: a radio or a segmented control.
- An immediate action like “Done” on an action: a button or the action row's own check.
Rules
Do
Positive label: “Send email notifications”.
Don't
Negative label: “Don't send email notifications”; checking it becomes a double negative.
Do
An option that stands alone in a form: boxed, with a description.
Don't
A checkbox with no description whose consequence is unclear.
Do
Checkbox from components/controls.
Don't
A raw <input type="checkbox">; the browser draws a gray square or a cold blue.
Accessibility and direction
- The native input is kept, so the checkbox role, the checked and mixed states, and Space all work on their own.
- Without a visible label, ariaLabel is required.
- An error sets aria-invalid, and the reason is written in text under the group, not shown with color alone.
- The box sits next to the label with a logical gap, so it's on the right in right-to-left and on the left in left-to-right; the check mark doesn't mirror.
- The white check on --accent has a contrast of about 3.5 to 1, which is enough for a graphical symbol (3 to 1).
Code
import { Checkbox } from "@/components/controls";
<Checkbox checked={isGroup} onChange={setIsGroup} label={tr("جلسه گروهی")} />
<Checkbox
boxed
checked={auto}
onChange={setAuto}
label={tr("اقدام پرداخت خودکار بساز")}
description={tr("۵ روز مانده به هر سررسید، «پرداخت …» در اقدامات این شرکت ساخته میشود.")}
/>Related pages