Button Segmented
Segmented control for selecting options.
Button Segmented Examples
Copy-ready examples with live previews.
Basic usage
Controlled segmented control: you own `value` and update it via `onValueChange`.
Live preview
Single select (default)
import { useState } from "react";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
export default function Example() {
const [value, setValue] = useState("day");
return (
<Button_segmented
ariaLabel="Time range"
value={value}
onValueChange={setValue}
items={[
{ id: "day", label: "Day" },
{ id: "week", label: "Week" },
{ id: "month", label: "Month", disabled: true },
]}
/>
);
}Live preview
Multi select
import { useState } from "react";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
export default function Example() {
const [value, setValue] = useState<string[]>(["bold"]);
return (
<Button_segmented
mode="multi"
ariaLabel="Text style"
value={value}
onValueChange={setValue}
items={[
{ id: "bold", label: "Bold" },
{ id: "italic", label: "Italic" },
{ id: "underline", label: "Underline" },
]}
/>
);
}Tone + size
Switch surface tone (light vs solid) and apply size presets.
Live preview
Tone (light vs solid) + size (sm/md/lg)
import { useState } from "react";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
import type { ISegmentedProps } from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented.type";
type V = ISegmentedProps["value"];
export default function Example() {
const [tonePick, setTonePick] = useState<V>("light");
const [sizePick, setSizePick] = useState<V>("md");
const tone = (tonePick === "solid" ? "solid" : "light") as ISegmentedProps["tone"];
return (
<>
<Button_segmented
ariaLabel="Surface tone"
mode="single"
size="small"
variant="secondary"
value={tonePick}
onValueChange={setTonePick}
items={[
{ id: "light", label: "Light" },
{ id: "solid", label: "Solid" },
]}
/>
<Button_segmented
ariaLabel="Size preset"
mode="single"
size="medium"
variant="primary"
tone={tone}
value={sizePick}
onValueChange={setSizePick}
items={[
{ id: "sm", label: "SM" },
{ id: "md", label: "MD" },
{ id: "lg", label: "LG", disabled: true },
]}
/>
</>
);
}Variants
Same value, different visual variants.
Live preview
Variants list
import { useState } from "react";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
import type { ISegmentedProps } from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented.type";
type V = ISegmentedProps["value"];
export default function Example() {
const [value, setValue] = useState<V>("md");
const [tonePick, setTonePick] = useState<V>("light");
const tone = (tonePick === "solid" ? "solid" : "light") as ISegmentedProps["tone"];
return (
<>
<Button_segmented
ariaLabel="Tone"
mode="single"
size="small"
variant="secondary"
value={tonePick}
onValueChange={setTonePick}
items={[
{ id: "light", label: "Light" },
{ id: "solid", label: "Solid" },
]}
/>
{(["primary", "secondary", "tertiary", "success", "warning", "danger", "info"] as const).map((variant) => (
<div key={variant} style={{ marginTop: 10 }}>
<Button_segmented
ariaLabel={`Variant ${variant}`}
mode="single"
size="small"
variant={variant}
tone={tone}
value={value}
onValueChange={setValue}
items={[
{ id: "sm", label: "SM" },
{ id: "md", label: "MD" },
{ id: "lg", label: "LG" },
]}
/>
</div>
))}
</>
);
}Multi-select with icons
Show an icon only when an item is selected.
Live preview
Filters with check icon
import { useState } from "react";
import Icon from "@/packages/ui/src/_components/icon/Icon";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
import type { ISegmentedProps } from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented.type";
type V = ISegmentedProps["value"];
const has = (v: V, id: string) => Array.isArray(v) && v.includes(id);
export default function Example() {
const [filters, setFilters] = useState<V>(["new", "sale"]);
return (
<Button_segmented
ariaLabel="Filters"
mode="multi"
size="medium"
variant="success"
tone="solid"
value={filters}
onValueChange={setFilters}
items={[
{ id: "new", label: "New", icon: has(filters, "new") ? <Icon name="Check" size="small" /> : undefined },
{ id: "sale", label: "Sale", icon: has(filters, "sale") ? <Icon name="Check" size="small" /> : undefined },
{ id: "vip", label: "VIP", icon: has(filters, "vip") ? <Icon name="Check" size="small" /> : undefined },
{ id: "arch", label: "Archived", disabled: true },
]}
/>
);
}Icon-only items
When you render icons without labels, provide item-level `ariaLabel`.
• In `single` mode, the component uses `role='radiogroup'` and each item uses `aria-checked`.
Live preview
Icon-only switcher
import { useState } from "react";
import Icon from "@/packages/ui/src/_components/icon/Icon";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
import type { ISegmentedProps } from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented.type";
type V = ISegmentedProps["value"];
export default function Example() {
const [view, setView] = useState<V>("grid");
return (
<Button_segmented
ariaLabel="Change view"
mode="single"
size="small"
variant="info"
value={view}
onValueChange={setView}
items={[
{ id: "grid", label: "", icon: <Icon name="Home" size="small" />, ariaLabel: "Grid view" },
{ id: "list", label: "", icon: <Icon name="List" size="small" />, ariaLabel: "List view" },
{ id: "map", label: "", icon: <Icon name="Map" size="small" />, ariaLabel: "Map view" },
]}
/>
);
}Multi-select mapped to booleans
Useful when your state is not an array, but a set of booleans.
Live preview
Wi‑Fi / BT / GPS mapped to booleans
import { useMemo, useState } from "react";
import Icon from "@/packages/ui/src/_components/icon/Icon";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
import type { ISegmentedProps } from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented.type";
type Item = ISegmentedProps["items"][number];
export default function Example() {
const [wifi, setWifi] = useState(true);
const [bt, setBt] = useState(false);
const [gps, setGps] = useState(true);
const items: Item[] = useMemo(
() => [
{ id: "wifi", label: "Wi‑Fi", icon: wifi ? <Icon name="Check" size="small" /> : undefined, ariaLabel: "Toggle Wi‑Fi" },
{ id: "bt", label: "BT", icon: bt ? <Icon name="Check" size="small" /> : undefined, ariaLabel: "Toggle Bluetooth" },
{ id: "gps", label: "GPS", icon: gps ? <Icon name="Check" size="small" /> : undefined, ariaLabel: "Toggle GPS" },
],
[wifi, bt, gps]
);
return (
<Button_segmented
ariaLabel="Quick toggles"
mode="multi"
variant="warning"
value={[...(wifi ? ["wifi"] : []), ...(bt ? ["bt"] : []), ...(gps ? ["gps"] : [])]}
onValueChange={(next) => {
const arr = Array.isArray(next) ? next : [];
setWifi(arr.includes("wifi"));
setBt(arr.includes("bt"));
setGps(arr.includes("gps"));
}}
items={items}
/>
);
}Full width + long labels
Stretch the control to the container width and verify ellipsis behavior.
Live preview
fullWidth + long labels
import { useState } from "react";
import Button_segmented from "@/packages/ui/src/_components/buttons_variants/button_segmented/Button_segmented";
export default function Example() {
const [value, setValue] = useState("archive");
return (
<div style={{ maxWidth: 520 }}>
<Button_segmented
ariaLabel="Long labels"
mode="single"
fullWidth
size="large"
variant="danger"
tone="solid"
value={value}
onValueChange={setValue}
items={[
{ id: "delete", label: "Delete current selection (danger)" },
{ id: "archive", label: "Archive for later review" },
{ id: "restore", label: "Restore (disabled)", disabled: true },
]}
/>
</div>
);
}On this page
Button Segmented Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| items | Array<{ id: string; label?: string; icon?: ReactNode; disabled?: boolean; ariaLabel?: string }> | Yes | — | Items rendered as segmented buttons. |
| mode | "single" | "multi" | No | "single" | Selection mode. In single, only one item can be selected. In multi, multiple can be toggled on/off. |
| value | string | string[] | Yes | — | Controlled value. Use string for mode='single', and string[] for mode='multi'. |
| onValueChange | (next: string | string[]) => void | Yes | — | Called when selection changes. Payload depends on mode. |
| ariaLabel | string | No | — | Accessible label for the group container (aria-label). |
| size | "small" | "medium" | "large" | No | "medium" | Size preset for the segmented control and each inner Button. |
| variant | "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "info" | No | "primary" | Visual variant applied to the root. |
| tone | "light" | "solid" | No | "light" | Surface tone. solid adds a modifier class; light adds none. |
| fullWidth | boolean | No | false | Makes the control stretch to full width (CSS class). |
| className | string | No | — | Extra classes for the root container. |