XDSSegmentedControl@xds/core · SegmentedControl

Usage

A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.

Best practices

GuidancePractices
DoUse for switching between 2–5 mutually exclusive views or modes where all options should be visible.
DoProvide a descriptive label for the control to ensure the group is accessible to screen readers.
Don'tUse for page-level navigation — use XDSTabList instead. TabList is a navigation component, while SegmentedControl is an input that always has exactly one selected option.
Don'tUse for simple on/off states — use XDSToggleButton instead. ToggleButton can be toggled on or off independently, while SegmentedControl enforces a single selection from a group.

Import

ts
import {XDSSegmentedControl} from '@xds/core/SegmentedControl'

Props

PropTypeDescription
valuerequired
stringThe currently selected value (controlled).
onChangerequired
(value: string) => voidCallback fired when a segment is selected.
labelrequired
stringAccessible label for the radio group (used as aria-label, never rendered visually).
childrenrequired
ReactNodeXDSSegmentedControlItem children.
size
'sm' | 'md' | 'lg' (default: 'md')Size variant for the control.
layout
'hug' | 'fill' (default: 'hug')Layout mode. hug (default) sizes segments to content; fill stretches them equally to fill the container.
isDisabled
boolean (default: false)Whether the entire control is disabled.
xstyle
StyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value — not an inline style object like style={{}}.

Sub-components

SegmentedControl is a compound component with 2 sub-components.

XDSSegmentedControl

Container wrapper providing context (value, onChange, size, isDisabled) to XDSSegmentedControlItem children.
PropTypeDescription
valuerequired
stringThe currently selected value (controlled).
onChangerequired
(value: string) => voidCallback fired when a segment is selected.
labelrequired
stringAccessible label for the radio group (used as aria-label, never rendered visually).
childrenrequired
ReactNodeXDSSegmentedControlItem children.
size
'sm' | 'md' | 'lg' (default: 'md')Size variant for the control.
layout
'hug' | 'fill' (default: 'hug')Layout mode. hug (default) sizes segments to content; fill stretches them equally to fill the container.
isDisabled
boolean (default: false)Whether the entire control is disabled.
xstyle
StyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value — not an inline style object like style={{}}.

XDSSegmentedControlItem

Individual segment item rendering as a radio button within the segmented control.
PropTypeDescription
valuerequired
stringUnique value for this segment, matched against the parent value.
labelrequired
stringAccessible label for this segment. Rendered as visible text unless isLabelHidden is true.
isLabelHidden
boolean (default: false)Whether the label is visually hidden. When true, only the icon is displayed and label is used as aria-label.
icon
ReactNodeIcon element displayed before the label.
isDisabled
boolean (default: false)Whether this individual item is disabled.

Examples

Common configurations, variations, and states.
SegmentedControl — Disabled ItemSegmented control with an individually disabled option for unavailable choices.
tsx
'use client';
import {useState} from 'react';
import {
XDSSegmentedControl,
XDSSegmentedControlItem,
} from '@xds/core/SegmentedControl';
export default function SegmentedControlDisabledItem() {
const [value, setValue] = useState('hourly');
return (
<XDSSegmentedControl
value={value}
onChange={setValue}
label="Data granularity">
<XDSSegmentedControlItem value="hourly" label="Hourly" />
<XDSSegmentedControlItem value="daily" label="Daily" />
<XDSSegmentedControlItem value="weekly" label="Weekly" isDisabled />
</XDSSegmentedControl>
);
}
SegmentedControl — Icon OnlyCompact segmented control with hidden labels, showing only icons for space-constrained layouts.
tsx
'use client';
import {useState} from 'react';
import {
XDSSegmentedControl,
XDSSegmentedControlItem,
} from '@xds/core/SegmentedControl';
const GridIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="14" y="3" width="7" height="7" rx="1" />
<rect x="3" y="14" width="7" height="7" rx="1" />
<rect x="14" y="14" width="7" height="7" rx="1" />
</svg>
);
const ListIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
<line x1="9" y1="6" x2="20" y2="6" />
<line x1="9" y1="12" x2="20" y2="12" />
<line x1="9" y1="18" x2="20" y2="18" />
<circle cx="5" cy="6" r="1" fill="currentColor" />
<circle cx="5" cy="12" r="1" fill="currentColor" />
<circle cx="5" cy="18" r="1" fill="currentColor" />
</svg>
);
export default function SegmentedControlIconOnly() {
const [value, setValue] = useState('grid');
return (
<XDSSegmentedControl
value={value}
onChange={setValue}
label="View mode"
size="sm">
<XDSSegmentedControlItem
value="grid"
label="Grid"
isLabelHidden
icon={<GridIcon />}
/>
<XDSSegmentedControlItem
value="list"
label="List"
isLabelHidden
icon={<ListIcon />}
/>
</XDSSegmentedControl>
);
}
SegmentedControl — With IconsSegmented control with icon and label pairs for a view mode switcher.
tsx
'use client';
import {useState} from 'react';
import {
XDSSegmentedControl,
XDSSegmentedControlItem,
} from '@xds/core/SegmentedControl';
const GridIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="14" y="3" width="7" height="7" rx="1" />
<rect x="3" y="14" width="7" height="7" rx="1" />
<rect x="14" y="14" width="7" height="7" rx="1" />
</svg>
);
const ListIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
<line x1="9" y1="6" x2="20" y2="6" />
<line x1="9" y1="12" x2="20" y2="12" />
<line x1="9" y1="18" x2="20" y2="18" />
<circle cx="5" cy="6" r="1" fill="currentColor" />
<circle cx="5" cy="12" r="1" fill="currentColor" />
<circle cx="5" cy="18" r="1" fill="currentColor" />
</svg>
);
const TableIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2" />
<line x1="3" y1="9" x2="21" y2="9" />
<line x1="3" y1="15" x2="21" y2="15" />
<line x1="9" y1="3" x2="9" y2="21" />
</svg>
);
export default function SegmentedControlWithIcons() {
const [value, setValue] = useState('grid');
return (
<XDSSegmentedControl value={value} onChange={setValue} label="View mode">
<XDSSegmentedControlItem value="grid" label="Grid" icon={<GridIcon />} />
<XDSSegmentedControlItem value="list" label="List" icon={<ListIcon />} />
<XDSSegmentedControlItem
value="table"
label="Table"
icon={<TableIcon />}
/>
</XDSSegmentedControl>
);
}
SegmentedControl \u2014 Fill LayoutSegmented control that stretches segments equally to fill the available width, useful for fixed-width containers.
tsx
'use client';
import {useState} from 'react';
import {
XDSSegmentedControl,
XDSSegmentedControlItem,
} from '@xds/core/SegmentedControl';
export default function SegmentedControlFillLayout() {
const [value, setValue] = useState('weekly');
return (
<div style={{width: 400}}>
<XDSSegmentedControl
value={value}
onChange={setValue}
label="Time range"
layout="fill">
<XDSSegmentedControlItem value="daily" label="Daily" />
<XDSSegmentedControlItem value="weekly" label="Weekly" />
<XDSSegmentedControlItem value="monthly" label="Monthly" />
</XDSSegmentedControl>
</div>
);
}

Showcase source

tsx
'use client';
import {
XDSSegmentedControl,
XDSSegmentedControlItem,
} from '@xds/core/SegmentedControl';
export default function SegmentedControlShowcase() {
return (
<XDSSegmentedControl value="grid" onChange={() => {}} label="View mode">
<XDSSegmentedControlItem value="grid" label="Grid" />
<XDSSegmentedControlItem value="list" label="List" />
<XDSSegmentedControlItem value="table" label="Table" />
</XDSSegmentedControl>
);
}