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

Do
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}
    />
  );
}
A mode or a range chosen in place: the caller owns value, and label names the group.
Don't
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}
    />
  );
}
An on/off setting is a Checkbox, not a two-option SegmentedControl.

Disabled reason

Do
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}
    />
  );
}
An option that cannot be chosen yet stays in the group with a title that says why.
Don't
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}
    />
  );
}
A disabled option with no title leaves the person guessing why it is greyed out.

Links

Do
import { SegmentedControl } from "@hackcove/ui";

<SegmentedControl
  label="Journal"
  value="daily"
  items={[
    { value: "daily", label: "Daily", href: "#daily" },
    { value: "weekly", label: "Weekly", href: "#weekly" },
  ]}
/>
Options that go to another page are links: href on each, and value marks the current page.

Usage

  • Two to five short options. The caller owns value and onChange; label names the group.
  • An on/off setting is a Checkbox; a long list is a Select.
  • Switching the panel under a row of headings is Tabs.
  • A count sits muted after the label.
  • A disabled option keeps a title as the reason; disabled on the group disables every option.
  • Options that go to another page are links: href on each, or render to draw the app's own router link. value marks the current page.

Accessibility

  • Buttons form a radiogroup named by label; each option is a radio with aria-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 its title is read out; the arrow keys skip it.
  • Links form a <nav> named by label, and the current one has aria-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.


disabled

Every option is disabled, e.g. until the page has hydrated.

Type
boolean

items required
Type
SwitchButton[] | SwitchLink[]

label required

The accessible name of the group.

Type
string

onChange

Called with the option's value when one is chosen, by click or arrow key.

Type
((value: string) => void)

value required

The value of the current option.

Type
string