Segment
A segmented control component for single-select, supporting controlled, uncontrolled and options-driven modes
Installation
Usage
Basic Usage
Data-driven segmented control for single-select, supporting controlled and uncontrolled modes.
Selected: list
"use client";import { useState } from "react";import { SegmentGroup } from "@/ui";export default function Demo() { const [value, setValue] = useState("list"); return ( <div className="flex flex-col gap-3"> <SegmentGroup value={value} onValueChange={setValue} options={[ { label: "List", value: "list" }, { label: "Grid", value: "grid" }, { label: "Table", value: "table" }, ]} /> <p className="text-sm text-muted-foreground">Selected: {value}</p> </div> );}Custom
Assemble segments manually with controlled parts; the composite uses a pure color transition by default and ships without a sliding indicator — add one yourself if needed.
"use client";import { useState } from "react";import { Segment } from "@/ui";const options = [ { label: "Day", value: "day" }, { label: "Week", value: "week" }, { label: "Month", value: "month" },];export default function Demo() { const [value, setValue] = useState("week"); const activeIndex = options.findIndex((option) => option.value === value); return ( <div role="radiogroup" className="relative grid w-72 grid-flow-col auto-cols-fr overflow-hidden rounded-md border border-border bg-muted" > <div aria-hidden className="absolute inset-y-0 bg-primary transition-[left] duration-200 ease-out" style={{ left: `${(activeIndex / options.length) * 100}%`, width: `${100 / options.length}%`, }} /> {options.map((option) => ( <Segment key={option.value} checked={value === option.value} onClick={() => setValue(option.value)} className="relative border-0 bg-transparent aria-checked:bg-transparent" > {option.label} </Segment> ))} </div> );}API Reference
High-level Components
Ready-to-use composite component.
SegmentGroup
| Prop | Type | Default | Description |
|---|---|---|---|
options | SegmentOptionConfig[] | - | Options data array |
value | string | - | Controlled selected value |
defaultValue | string | - | Default selected value (uncontrolled) |
onValueChange | (value: string) => void | - | Callback when the selected value changes |
disabled | boolean | false | Disable all options |
className | ClassNameValue | - | Custom class names, applied to the container |
itemClassName | ClassNameValue | - | Custom class names, applied to each segment |
Keyboard: the group is a radio group with roving tabindex — ArrowRight / ArrowDown / ArrowLeft / ArrowUp move to (and select) the next / previous enabled option, Home / End jump to the first / last one, Enter / Space activate the focused option.
SegmentOptionConfig
| Field | Type | Default | Description |
|---|---|---|---|
label | string | - | Option display text |
value | string | - | Unique identifier value |
disabled | boolean | false | Disable the option |
className | ClassNameValue | - | Custom class names, overrides itemClassName |
Composable Components
Segment
A single segment part with radio semantics: once checked, clicking again does not uncheck it. It carries no internal state — the checked state must be provided from outside, so it is only meaningful inside a SegmentGroup or a manually assembled group container.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | The segment content |
checked | boolean | false | Checked state, drives aria-checked and the checked styles |
className | ClassNameValue | - | Custom class names |
...props | React.ComponentProps<"button"> | - | Supports all native button props (except type), such as onClick, disabled |