All components

Segment Bar

Equal-width horizontal segments in a single row. Pass a data array of color classes with optional per-segment tooltips and aria labels. Segments animate in on mount, lift on hover and focus, and respect reduced motion.

Default
24-hour API health strip with status legend, weekly activity, and portfolio allocation bars.

API health (24h)

checkout-api

HealthyDegradedDownMaintenanceNo data

Weekly activity

Portfolio allocation

1import { cn } from "@/lib/utils";
2import { SegmentBar, type SegmentBarItem } from "@/registry/ui/segment-bar";
3
4type ApiHealthStatus = "healthy" | "degraded" | "down" | "maintenance" | "no-data";
5
6const apiHealthStyles: Record<
7 ApiHealthStatus,
8 { color: string; label: string }
9> = {
10 healthy: { color: "bg-emerald-500/85", label: "Healthy" },
11 degraded: { color: "bg-amber-500/85", label: "Degraded" },
12 down: { color: "bg-rose-500/85", label: "Down" },
13 maintenance: { color: "bg-sky-500/50", label: "Maintenance" },
14 "no-data": { color: "bg-muted", label: "No data" },
15};
16
17function formatHourLabel(hour: number): string {
18 const period = hour >= 12 ? "PM" : "AM";
19 const hour12 = hour % 12 === 0 ? 12 : hour % 12;
20 return `${hour12}:00 ${period}`;
21}
22
23/** Sample hourly API health for a checkout service (24 segments). */
24const hourlyApiHealth: Array<{
25 hour: number;
26 status: ApiHealthStatus;
27 detail?: string;
28}> = [
29 { hour: 0, status: "healthy", detail: "38ms p99 · 100% success" },
30 { hour: 1, status: "healthy", detail: "35ms p99 · 100% success" },
31 { hour: 2, status: "maintenance", detail: "DB migration window" },
32 { hour: 3, status: "maintenance", detail: "DB migration window" },
33 { hour: 4, status: "healthy", detail: "41ms p99 · 100% success" },
34 { hour: 5, status: "healthy", detail: "44ms p99 · 100% success" },
35 { hour: 6, status: "healthy", detail: "52ms p99 · 99.99% success" },
36 { hour: 7, status: "healthy", detail: "61ms p99 · 99.98% success" },
37 { hour: 8, status: "healthy", detail: "74ms p99 · 99.97% success" },
38 { hour: 9, status: "degraded", detail: "186ms p99 · 1.4% 5xx" },
39 { hour: 10, status: "healthy", detail: "68ms p99 · 99.96% success" },
40 { hour: 11, status: "healthy", detail: "59ms p99 · 99.98% success" },
41 { hour: 12, status: "degraded", detail: "312ms p99 · 2.8% 5xx" },
42 { hour: 13, status: "degraded", detail: "278ms p99 · 1.9% 5xx" },
43 { hour: 14, status: "healthy", detail: "71ms p99 · 99.97% success" },
44 { hour: 15, status: "degraded", detail: "deploy canary · 240ms p99" },
45 { hour: 16, status: "healthy", detail: "63ms p99 · 99.98% success" },
46 { hour: 17, status: "degraded", detail: "412ms p99 · queue backlog" },
47 { hour: 18, status: "down", detail: "incident #4821 · payment gateway" },
48 { hour: 19, status: "degraded", detail: "recovery · 520ms p99" },
49 { hour: 20, status: "healthy", detail: "58ms p99 · 99.95% success" },
50 { hour: 21, status: "healthy", detail: "49ms p99 · 99.98% success" },
51 { hour: 22, status: "healthy", detail: "42ms p99 · 100% success" },
52 { hour: 23, status: "no-data", detail: "metrics delayed" },
53];
54
55const dailyApiHealth: SegmentBarItem[] = hourlyApiHealth.map(
56 ({ hour, status, detail }) => {
57 const { color, label } = apiHealthStyles[status];
58 const time = formatHourLabel(hour);
59 const suffix = detail ? ` · ${detail}` : "";
60
61 return {
62 id: `hour-${hour}`,
63 color,
64 tooltip: `${time} - ${label}${suffix}`,
65 ariaLabel: `${time}, ${label}${suffix}`,
66 };
67 },
68);
69
70const weeklyActivity: SegmentBarItem[] = [
71 { id: "mon", color: "bg-emerald-500/90", tooltip: "Mon - 4 sessions" },
72 { id: "tue", color: "bg-emerald-500/70", tooltip: "Tue - 3 sessions" },
73 { id: "wed", color: "bg-emerald-500/50", tooltip: "Wed - 2 sessions" },
74 { id: "thu", color: "bg-emerald-500/90", tooltip: "Thu - 4 sessions" },
75 { id: "fri", color: "bg-emerald-500/30", tooltip: "Fri - 1 session" },
76 {
77 id: "sat",
78 color: "bg-muted",
79 tooltip: "Sat - rest day",
80 ariaLabel: "Saturday rest day",
81 },
82 { id: "sun", color: "bg-emerald-500/60", tooltip: "Sun - 2 sessions" },
83];
84
85const portfolioAllocation: SegmentBarItem[] = [
86 { id: "equities", color: "bg-sky-500/90", tooltip: "Equities - 42%" },
87 { id: "bonds", color: "bg-indigo-500/80", tooltip: "Bonds - 28%" },
88 { id: "cash", color: "bg-amber-500/70", tooltip: "Cash - 18%" },
89 {
90 id: "alternatives",
91 color: "bg-rose-500/80",
92 tooltip: "Alternatives - 12%",
93 },
94];
95
96export function SegmentBarExamples() {
97 return (
98 <div className="mx-auto flex w-full max-w-xl flex-col gap-8 py-6">
99 <div className="space-y-2">
100 <div className="flex items-baseline justify-between gap-2">
101 <p className="text-sm text-muted-foreground">API health (24h)</p>
102 <p className="text-xs text-muted-foreground">checkout-api</p>
103 </div>
104 <SegmentBar data={dailyApiHealth} defaultBackgroundColor="bg-muted" />
105 <div className="flex flex-wrap gap-x-4 gap-y-1 pt-1 text-xs text-muted-foreground">
106 {(
107 Object.entries(apiHealthStyles) as Array<
108 [ApiHealthStatus, { color: string; label: string }]
109 >
110 ).map(([status, { color, label }]) => (
111 <span key={status} className="inline-flex items-center gap-1.5">
112 <span className={cn("size-2 rounded-[1px]", color)} aria-hidden />
113 {label}
114 </span>
115 ))}
116 </div>
117 </div>
118
119 <div className="space-y-2">
120 <p className="text-sm text-muted-foreground">Weekly activity</p>
121 <SegmentBar data={weeklyActivity} />
122 </div>
123
124 <div className="space-y-2">
125 <p className="text-sm text-muted-foreground">Portfolio allocation</p>
126 <SegmentBar
127 data={portfolioAllocation}
128 defaultBackgroundColor="bg-muted"
129 />
130 </div>
131 </div>
132 );
133}

Installation & source

Install via the shadcn CLI or copy the registry files manually.

bash
npx shadcn@latest add @tt-ui/segment-bar

Props

NameTypeDefaultDescription
dataSegmentBarItem[][]Segment definitions: color classes, tooltip content, and optional aria labels
defaultBackgroundColorstring"bg-secondary"Tailwind background class for segments without a color
disabledTooltipbooleanfalseDisables tooltips for every segment in the bar
classNamestringundefinedAdditional classes on the root container