Skip to content
Highlight

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

tsx
import { Checkbox } from '@highlight/ui'

Change the props; the preview and the snippet update together.

Props
Checked
Indeterminate
Disabled
tsx
<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.

Sent once the summary is ready.

tsx
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.

tsx
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

tsx
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.

tsx
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.