V2 componentsUpdated Oct 15, 2026
Checkbox
A choice collected now and acted on later, or one of several picked from a list. Use Toggle instead when flipping it applies a setting immediately. 16px, a hairline edge on the raised ground, and the blue on-fill Toggle shares. Put it in a Field with orientation="leading" so the label is part of the hit target and a note sits under it. For several checkboxes answering one question, use Checkbox.Group in a Field with each option in a Field.Item.
Source: packages/ui/src/components/checkbox
import { Checkbox } from '@highlight/ui'Change the props; the preview and the snippet update together.
<Field orientation="leading"> <Checkbox checked onCheckedChange={setChecked}> <Checkbox.Indicator /> </Checkbox> <Field.Label> Email me a recap </Field.Label></Field>Each sits in a Field with orientation="leading": the box on the label’s first line, the note under the label, and the label a hit target. Disabled works like a disabled Button: one disabled wash checked or not, with the mark in the disabled ink, so never make it the only place a fact appears.
import { Checkbox, Field } from '@highlight/ui' export default function CheckboxBasic() { return ( <Field.Group orientation="leading" className="max-w-sm"> <Field> <Checkbox defaultChecked> <Checkbox.Indicator /> </Checkbox> <Field.Label>Email me a recap after each meeting</Field.Label> <Field.Note>Sent once the summary is ready.</Field.Note> </Field> <Field> <Checkbox> <Checkbox.Indicator /> </Checkbox> <Field.Label>Share transcripts with my team</Field.Label> </Field> <Field disabled> <Checkbox defaultChecked> <Checkbox.Indicator /> </Checkbox> <Field.Label>Managed by your organization</Field.Label> </Field> </Field.Group> )}A single checkbox with checked and onCheckedChange, the same shape as Base UI.
Post meeting summaries to your channel.
Syncing is on.
import { useState } from 'react'import { Checkbox, Field } from '@highlight/ui' export default function CheckboxControlled() { const [checked, setChecked] = useState(true) return ( <div className="flex flex-col gap-3"> <Field orientation="leading"> <Checkbox checked={checked} onCheckedChange={setChecked}> <Checkbox.Indicator /> </Checkbox> <Field.Label>Sync to Slack</Field.Label> <Field.Note>Post meeting summaries to your channel.</Field.Note> </Field> <p className="text-foreground-secondary text-xs">Syncing is {checked ? 'on' : 'off'}.</p> </div> )}Checkbox.Group holds one string[] value; each Checkbox takes a value. Options are Field.Items, as in RadioGroup, so a disabled option greys its own label and note.
Ask an admin to connect it.
Sync to: Slack
import { useState } from 'react'import { Checkbox, Field } from '@highlight/ui' const SOURCES = ['Slack', 'Linear', 'Notion'] as const export default function CheckboxGroupExample() { const [value, setValue] = useState<Array<string>>(['Slack']) return ( <div className="flex flex-col gap-3"> <Field> <Checkbox.Group value={value} onValueChange={setValue} aria-label="Sync to"> {SOURCES.map((name) => ( <Field.Item key={name}> <Checkbox value={name}> <Checkbox.Indicator /> </Checkbox> <Field.Label>{name}</Field.Label> </Field.Item> ))} <Field.Item disabled> <Checkbox value="Jira"> <Checkbox.Indicator /> </Checkbox> <Field.Label>Jira</Field.Label> <Field.Note>Ask an admin to connect it.</Field.Note> </Field.Item> </Checkbox.Group> </Field> <p className="text-foreground-secondary text-xs">Sync to: {value.length ? value.join(', ') : 'nothing'}</p> </div> )}Give the group allValues and mark one Checkbox parent: it shows a dash over a partial selection, selects all when checked and clears when unchecked, with no state of its own.
import { useState } from 'react'import { Checkbox, Field } from '@highlight/ui' const SOURCES = ['Slack', 'Linear', 'Notion'] export default function CheckboxIndeterminate() { const [value, setValue] = useState<Array<string>>(['Slack']) return ( <Field> <Checkbox.Group value={value} onValueChange={setValue} allValues={SOURCES} aria-label="Sources"> <Field.Item> <Checkbox parent> <Checkbox.Indicator /> </Checkbox> <Field.Label>All sources</Field.Label> </Field.Item> {SOURCES.map((name) => ( <Field.Item key={name} className="pl-6"> <Checkbox value={name}> <Checkbox.Indicator /> </Checkbox> <Field.Label>{name}</Field.Label> </Field.Item> ))} </Checkbox.Group> </Field> )}The root, then any compound sub-components. Every part accepts className and forwards the rest of its props to the element or Base UI part beneath it.
Checkbox- Base UI Checkbox.Root. The 16px box; checked, indeterminate, disabled and onCheckedChange live here.
Checkbox.Group- Base UI CheckboxGroup. One string[] value (value, defaultValue, onValueChange); allValues enables a parent Checkbox. A part, not the root: most checkboxes stand alone.
Checkbox.Indicator- The check, or a dash while indeterminate. Fades and grows in from 60%. Pass children to replace both glyphs.
- All Base UI Checkbox.Root props pass through: name, value, parent, indeterminate, required, readOnly.