Interactive Answers
Radial Dots
A cycle as rings of dots — hours of the day or days of the week, stacked by series, with the headline in the middle.
2 variantsMIT
Preview
Runs by hour
invoice-agent · last 7 days, UTC
32 s
per run
Started by peopleScheduledRetries
Installation
Copies the component into components/ui and installs its dependencies and theme tokens.
pnpm dlx shadcn@latest add https://tuffui.com/r/radial-dots.jsonUsage
Pass your own data and wire the callbacks to your agent runtime.
import { RadialDots } from "@/components/ui/radial-dots";
export function RunsByHour({ stats }: { stats: HourlyStats }) {
return (
<RadialDots
title="Runs by hour"
subtitle="Last 7 days, UTC"
labels={stats.hours} // "00" … "23"
series={[
{ id: "people", label: "Started by people", values: stats.manual },
{ id: "scheduled", label: "Scheduled", values: stats.scheduled },
]}
center={{ value: `${stats.medianSeconds} s`, caption: "per run" }}
onSelect={(hour) => filterRuns(hour)}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| labels* | string[] | — | One label per sector, clockwise from the top. |
| series* | RadialSeries[] | — | Stacked outward in order. The busiest sector fills every ring. |
| title* | string | — | Header title. |
| subtitle | string | — | Secondary line under the title. |
| center* | { value: string; caption?: string } | — | Headline in the middle. Hovering a sector shows its numbers there instead. |
| axis | number[] | — | Indexes of the labels drawn around the edge. Defaults to the four quarters. |
| format | (value: number) => string | — | Formats sector values. Defaults to 1,234. |
| onSelect | (index: number) => void | — | Called when a sector is hovered or reached with the arrow keys. |
| className | string | — | Extra classes for the root element. |
type RadialSeries = {
id: string;
label: string;
values: number[]; // one per sector
color?: string; // defaults to brand, foreground, muted
};