SegmentedControl
A joined group of options where one is filled.
Overview
A mode or a range chosen in place: daily or weekly, split or even.
Mode
import { useState } from "react";
import { SegmentedControl } from "@hackcove/ui";
function Example() {
const [value, setValue] = useState("week");
return (
<SegmentedControl
label="Range"
items={[
{ value: "day", label: "Daily" },
{ value: "week", label: "Weekly" },
{ value: "month", label: "Monthly" },
]}
value={value}
onChange={setValue}
/>
);
}value, and label names the group.import { useState } from "react";
import { SegmentedControl } from "@hackcove/ui";
function Example() {
const [value, setValue] = useState("on");
return (
<SegmentedControl
label="Email me"
items={[
{ value: "on", label: "On" },
{ value: "off", label: "Off" },
]}
value={value}
onChange={setValue}
/>
);
}Checkbox, not a two-option SegmentedControl.Disabled reason
import { useState } from "react";
import { SegmentedControl } from "@hackcove/ui";
function Example() {
const [value, setValue] = useState("split");
return (
<SegmentedControl
label="Split"
items={[
{ value: "split", label: "Split" },
{ value: "even", label: "Even" },
{ value: "custom", label: "Custom", disabled: true, title: "Needs two or more people" },
]}
value={value}
onChange={setValue}
/>
);
}title that says why.import { useState } from "react";
import { SegmentedControl } from "@hackcove/ui";
function Example() {
const [value, setValue] = useState("split");
return (
<SegmentedControl
label="Split"
items={[
{ value: "split", label: "Split" },
{ value: "even", label: "Even" },
{ value: "custom", label: "Custom", disabled: true },
]}
value={value}
onChange={setValue}
/>
);
}title leaves the person guessing why it is greyed out.Links
import { SegmentedControl } from "@hackcove/ui";
<SegmentedControl
label="Journal"
value="daily"
items={[
{ value: "daily", label: "Daily", href: "#daily" },
{ value: "weekly", label: "Weekly", href: "#weekly" },
]}
/>href on each, and value marks the current page.Usage
- Two to five short options. The caller owns
valueandonChange;labelnames the group. - An on/off setting is a
Checkbox; a long list is aSelect. - Switching the panel under a row of headings is
Tabs. - A
countsits muted after the label. - A disabled option keeps a
titleas the reason;disabledon the group disables every option. - Options that go to another page are links:
hrefon each, orrenderto draw the app's own router link.valuemarks the current page.
Accessibility
- Buttons form a
radiogroupnamed bylabel; each option is aradiowitharia-checked. - The group is one tab stop. The arrow keys (all four), Home and End move to the next enabled option and choose it.
- A disabled option stays in the page as
aria-disabled, so itstitleis read out; the arrow keys skip it. - Links form a
<nav>named bylabel, and the current one hasaria-current="page". - The focus ring comes from the component.
API
SegmentedControl
A joined pill group where one option is filled: a mode or a range chosen in place. items are { value, label } buttons (value and onChange are the caller's state; the arrow keys, Home and End move the choice) or links (href, or render to draw the app's own router <Link>; value marks the current one, which gets aria-current). An item may carry a count, and a button one disabled (with a title for the reason); disabled on the group disables every option. label names the group.
disabledEvery option is disabled, e.g. until the page has hydrated.
- Type
boolean
items required- Type
SwitchButton[] | SwitchLink[]
label requiredThe accessible name of the group.
- Type
string
onChangeCalled with the option's value when one is chosen, by click or arrow key.
- Type
((value: string) => void)
value requiredThe value of the current option.
- Type
string