antuikit's Segmented is Ant Design's Segmented, with its option value type kept, item corners that stay concentric with the track at any theme radius, and option tooltips in the kit's small bubble. It adds no prop, and every prop passes through.
Install
npx antuikit@latest init
npx antuikit@latest add segmented
segmented.json also installs Tooltip, for the option tooltips. It needs no icon pack, since an option's icon takes whatever node you pass. Run the first command too, for AntuikitProvider.
Import
One component, no compound parts. An option is a plain object in options, not a child element, so there is no Segmented.Item to import.
import { Segmented } from "@/components/ui/segmented"
options takes bare strings or numbers, or option objects. Most of what you can set is on the option object: label and icon take nodes, which is how you render custom content per option.
1
{/* Bare values: the string is both the label and the value */}
{/* Objects, when the label and the value differ */}
5
<Segmented
6
options={[
7
{ label: "Daily", value: "d" },
8
{ label: "Weekly", value: "w" },
9
{ label: "Locked", value: "l", disabled: true },
10
]}
11
/>
disabled on the control takes the whole track out of the tab order. On an option it takes that one option out and leaves the rest usable. The selected option stays highlighted either way, so a disabled control still shows its setting.
There is no itemRender. Put custom content in each option's label and icon.
Typed values
Segmented is generic over its option values, and the kit keeps that. Add as const to the options array and onChange is typed with those values, so a useState setter fits with no cast.
An item's radius is the track's radius minus the track padding, at every size. Ant Design picks a fixed radius per size, which only lines up with the track at its default theme, so the kit works it out instead. Change borderRadius in your theme and the items follow the track.
shape="round" is left alone, since it is already a full pill.
The sliding thumb gets the same radius as the item, so the highlight keeps its shape as it moves.
Icon-only options
Each option is a real <input type="radio"> inside a <label>, so dropping the word drops the radio's accessible name with it, and nothing warns. Keep the word and hide it inside icon, not in label.
1
// Leave label unset: an empty label still adds a gap
2
// and pushes the glyph off center.
3
{
4
value: "light",
5
tooltip: "Light",
6
icon: (
7
<>
8
<Icon name="sun" />
9
<span className="sr-only">Light</span>
10
</>
11
),
12
}
The word names the radio because a <label> is named by its text, and icon renders inside it. An option's title does not name it.
Option tooltips have no arrow unless you pass arrow: true, and one bubble slides along the row. Once any option has a tooltip, a Tooltip of your own inside a label joins that bubble too.
Styling
classNames styles one part (root, item, label, icon), so use it first. className lands on the root and goes through cn().
The thumb has no part key, so reach it with a [&_.ant-segmented-thumb] selector.
Style the thumb and the selected item together. The thumb slides between options and the item takes over once it lands, so styling one alone changes the highlight mid-slide.
in-[.ant-segmented-item-selected]: in a label node styles it while its option is selected, with no state of your own.
1
{/* A flat thumb: no elevation, a neutral fill */}
2
<Segmented
3
options={VIEWS}
4
className="bg-transparent
5
[&_.ant-segmented-item-selected]:bg-fill-content
6
[&_.ant-segmented-item-selected]:shadow-none
7
[&_.ant-segmented-thumb]:bg-fill-content
8
[&_.ant-segmented-thumb]:shadow-none"
9
/>
10
11
{/* A solid track in theme classes, so it inverts in dark mode */}
12
<Segmented
13
options={VIEWS}
14
classNames={{
15
root: "bg-bg-solid",
16
item: "text-bg-base has-checked:text-text",
17
}}
18
/>
Setting --ant-segmented-item-selected-bg on the root has no effect. Style the selected item directly instead, and it works without !important.
API Reference
Segmented
Segmented's props. Rows marked antuikit in the Version column are added by the kit.