Skip to content
Highlight

V2 componentsUpdated Oct 15, 2026

Radio Group

Pick exactly one option from a short, always-visible set (2-6 options). One tab stop for the group; arrow keys move and select. Put the group in a Field and each option in a Field.Item with a Field.Label (and an optional Field.Note), the same label, note and disabled treatment as Checkbox; no separate label component. For a long list use Select; for independent on/off choices use Checkbox. A 16px blue dot control, with the invalid, disabled and focus states built in.

Source: packages/ui/src/components/radio-group

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

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

Props
Disabled
Invalid
Note on last
tsx
<Field>  <RadioGroup defaultValue="Summary only" aria-label="Meeting recap">    <Field.Item>      <RadioGroup.Item value="Summary only" />      <Field.Label>Summary only</Field.Label>    </Field.Item>    <Field.Item>      <RadioGroup.Item value="Summary and transcript" />      <Field.Label>Summary and transcript</Field.Label>    </Field.Item>    <Field.Item>      <RadioGroup.Item value="No recap" />      <Field.Label>No recap</Field.Label>    </Field.Item>  </RadioGroup></Field>

Uncontrolled with defaultValue. Field.Item disabled dims its radio, label and note together.

Sent once the transcript is ready.

Managed by your organization.

tsx
import { Field, RadioGroup } from '@highlight/ui' export default function RadioGroupBasic() {  return (    <Field className="max-w-sm">      <RadioGroup defaultValue="summary" aria-label="Meeting recap">        <Field.Item>          <RadioGroup.Item value="summary" />          <Field.Label>Summary only</Field.Label>        </Field.Item>        <Field.Item>          <RadioGroup.Item value="full" />          <Field.Label>Summary and transcript</Field.Label>          <Field.Note>Sent once the transcript is ready.</Field.Note>        </Field.Item>        <Field.Item disabled>          <RadioGroup.Item value="none" />          <Field.Label>No recap</Field.Label>          <Field.Note>Managed by your organization.</Field.Note>        </Field.Item>      </RadioGroup>    </Field>  )}

value and onValueChange, the same shape as Base UI.

Sync to: Slack

tsx
import { useState } from 'react'import { Field, RadioGroup } from '@highlight/ui' const OPTIONS = ['Slack', 'Linear', 'Notion'] as const export default function RadioGroupControlled() {  const [value, setValue] = useState<string>('Slack')   return (    <div className="flex flex-col gap-3">      <Field>        <RadioGroup value={value} onValueChange={(next) => setValue(String(next))} aria-label="Sync destination">          {OPTIONS.map((name) => (            <Field.Item key={name}>              <RadioGroup.Item value={name} />              <Field.Label>{name}</Field.Label>            </Field.Item>          ))}        </RadioGroup>      </Field>      <p className="text-foreground-secondary text-xs">Sync to: {value}</p>    </div>  )}

Field invalid turns every radio's edge and focus ring to danger; Field.Note error says why.

Pick a plan to continue.
tsx
import { Field, RadioGroup } from '@highlight/ui' export default function RadioGroupInvalid() {  return (    <Field invalid>      <RadioGroup aria-label="Plan" required>        <Field.Item>          <RadioGroup.Item value="team" />          <Field.Label>Team</Field.Label>        </Field.Item>        <Field.Item>          <RadioGroup.Item value="enterprise" />          <Field.Label>Enterprise</Field.Label>        </Field.Item>      </RadioGroup>      <Field.Note error match>        Pick a plan to continue.      </Field.Note>    </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.

RadioGroup
Base UI RadioGroup. Owns the selected value; holds the items.
RadioGroup.Item
One radio. Needs a value. Renders the dot by default; pass children to replace it.
RadioGroup.Indicator
The dot; scales in when checked. Only needed inside a custom Item.
  • Root props pass through from Base UI RadioGroup: name, value, defaultValue, onValueChange, disabled, readOnly, required.
  • Always give the group an accessible name: aria-label, or aria-labelledby pointing at a heading.