Segmented control
One choice from a few short options shown side by side, such as a message header type (No header / Text / Media / Location). For more options or longer labels, use a Radio group or a Select.
Installation
bun add @harmo-ui/css @harmo-ui/reactnpm install @harmo-ui/css @harmo-ui/reactpnpm add @harmo-ui/css @harmo-ui/reactyarn add @harmo-ui/css @harmo-ui/reactbunx harmo-ui add segmentednpx harmo-ui add segmentedpnpm dlx harmo-ui add segmentedyarn dlx harmo-ui add segmentedUsage
import { Segmented, SegmentedOption } from "@harmo-ui/react";
<Segmented label="Message header" name="header-type" defaultValue="none">
<SegmentedOption value="none">No header</SegmentedOption>
<SegmentedOption value="text">Text</SegmentedOption>
<SegmentedOption value="media">Media</SegmentedOption>
<SegmentedOption value="location">Location</SegmentedOption>
</Segmented>Examples
Options
Each option wraps a native radio, so the group works in forms, Tab reaches the chosen option, and the Arrow keys move the choice. role="radiogroup" names the group from its label.
<Segmented label="Message header" name="header-type" defaultValue="none">
<SegmentedOption value="none">No header</SegmentedOption>
<SegmentedOption value="text">Text</SegmentedOption>
<SegmentedOption value="media">Media</SegmentedOption>
<SegmentedOption value="location">Location</SegmentedOption>
</Segmented>Disabled option
disabled on an option's radio dims that option.
<Segmented label="Assign to" name="assign" defaultValue="team">
<SegmentedOption value="team">Team</SegmentedOption>
<SegmentedOption value="agent">Agent</SegmentedOption>
<SegmentedOption value="ai" disabled>
AI agent
</SegmentedOption>
</Segmented>Narrow container
Labels never wrap. When the options can't all fit on one row, drawn dashed here, they move to a new one.
<Segmented
label="Message header"
name="header-type-narrow"
defaultValue="none"
>
<SegmentedOption value="none">No header</SegmentedOption>
<SegmentedOption value="text">Text</SegmentedOption>
<SegmentedOption value="media">Media</SegmentedOption>
<SegmentedOption value="location">Location</SegmentedOption>
</Segmented>API reference
React
<Segmented> renders the group, with a <SegmentedOption> for each option; with label, it also renders the Field and label above it. Without label, name it with aria-label, or place it in a Setting, which names it. Other props are the group <div>'s attributes.
| Prop | Effect |
|---|---|
label | The label above it |
name | The name its options submit under; generated when left out |
value or defaultValue | The chosen option's value |
onValueChange | Called with the newly chosen value |
required, disabled | Set on every option |
<SegmentedOption> takes its value, its text as children, and optionally disabled. Its className and style go to the option's <label>, and its other props to the radio inside.
HTML
A <div class="hsegmented" role="radiogroup"> with aria-labelledby or aria-label. Each .hsegmented-option is a <label> wrapping an <input type="radio"> and its text, with the same name on every radio. Load segmented.css; field.css for the label. It needs no script.
| Hook | Effect |
|---|---|
checked on a radio | The chosen option |
disabled on a radio | That option dimmed, not-allowed cursor |
See Segmented control's full contract.
Accessibility
Each option wraps a native radio, so the group works in forms, Tab reaches the chosen option, and the Arrow keys move the choice. The radios are invisible but stay focusable, and role="radiogroup" with aria-labelledby names the group.