Segmented Control
A pill tab switcher with a sliding sky indicator that springs between options.
components/ui/segmented-control.tsx
"use client";
import * as React from "react";
export interface SegmentedControlProps {
options: string[];
value?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
className?: string;
}
export function SegmentedControl({
options,
value,
defaultValue,
onValueChange,
className = "",
}: SegmentedControlProps) {
const [inner, setInner] = React.useState(defaultValue ?? options[0]);
const active = value ?? inner;
const refs = React.useRef<(HTMLButtonElement | null)[]>([]);
const [box, setBox] = React.useState({ left: 0, width: 0 });
React.useLayoutEffect(() => {
const el = refs.current[options.indexOf(active)];
if (el) setBox({ left: el.offsetLeft, width: el.offsetWidth });
}, [active, options]);
const select = (option: string) => {
if (value === undefined) setInner(option);
onValueChange?.(option);
};
return (
<div
role="tablist"
className={["relative inline-flex rounded-full border border-white/15 p-[3px]", className].join(" ")}
>
<span
aria-hidden
className="absolute bottom-[3px] top-[3px] rounded-full bg-sky-300 transition-all duration-500 [transition-timing-function:cubic-bezier(.2,1.2,.4,1)]"
style={{ left: box.left, width: box.width }}
/>
{options.map((option, i) => (
<button
key={option}
ref={(el) => {
refs.current[i] = el;
}}
role="tab"
aria-selected={active === option}
onClick={() => select(option)}
className={[
"relative z-10 rounded-full px-[18px] py-1.5 text-[13px] transition-colors duration-300",
active === option ? "font-medium text-sky-950" : "text-zinc-400 hover:text-zinc-200",
].join(" ")}
>
{option}
</button>
))}
</div>
);
}Installation
01
Install with the shadcn CLI.
$ npx shadcn@latest add https://niceui.dev/r/segmented-control.json02
Or copy the source manually into components/ui/segmented-control.tsx. No extra dependencies.
Usage
import { SegmentedControl } from "@/components/ui/segmented-control";
export default function Example() {
return <SegmentedControl options={["Day", "Week", "Month"]} />;
}For AI assistants
This page is also available as Markdown and as a shadcn registry item. Use Copy prompt to hand the full source to Claude, Cursor or v0.