Segmented control
A few labelled options on a pill track, with a white thumb that glides to the one chosen.
ui.segmented-control
components/ui/segmented-control.tsxUse case
Use it when exactly one of two to five short options is always chosen and the choice changes what is shown: Day, Week and Month over a schedule, 7D, 30D and 90D over a sales figure, Open, Paid and All above invoices. It is controlled: the value lives in state and the view reads it.
Use it when
- Switching between views of the same content (Day, Week, Month)
- A date range over a figure or a chart
- A setting with two to five short options, one always chosen
Use something else when
- Sections of a page that each have their own panel: Tabs
- More options than fit on one line, or long labels: Select
- Icon switches that may combine or may all be off: Toggle group
- A choice in a form with a sentence for each option: Radio group
Examples
Code
Import
import { SegmentedControl } from "@/components/ui/segmented-control"Usage
const [view, setView] = useState<"day" | "week" | "month">("week")
<SegmentedControl
aria-label="View"
value={view}
onValueChange={setView}
options={[
{ value: "day", label: "Day" },
{ value: "week", label: "Week" },
{ value: "month", label: "Month" },
]}
/>Rules
- It is controlled: pass value and onValueChange, and keep the value in state.
- Always pass aria-label naming what is chosen (View, Range).
- Option labels are short and in Title Case.
- Each option is { value, label, disabled? }; size is sm, default or lg.
- The thumb slides to the one picked on the glide in --dur-slide; never swap a fill from one option to the other.
- It is exactly as tall as a Button of the same size (sm 30px, default 36px, lg 40px): in a row beside buttons, give both the same size, never a segmented control one size up.