Radial Bar Chart React component
A radial bar chart laid out like a clock: rounded bars radiate from a centre ring for each hour, coloured from quiet to busy, with ticks marking last week, a centre readout that follows the hovered hour and stat tiles for the peak and quietest times.
About the Radial Bar Chart component
Radial Bar Chart lays a daily cycle out like a clock: one rounded bar per hour radiating from the centre, longer and brighter when it's busier, with small ticks marking last week's value on each bar. It makes the rhythm of a day, when things pick up and when they go quiet, readable at a glance.
The centre shows the daily total and its change; hover, tap or use the arrow keys to read a single hour there instead. Tiles alongside give the peak hour, the quietest hour, how concentrated the day is and the week-over-week change.
When to use it
Use it for traffic, orders or support tickets by hour, energy use across a day, sleep or activity tracking, and any cyclical data with 12–36 slices (hours, months, days of the month).
For a few categories that aren't cyclical, a plain bar chart is easier to compare.
Installation
Add the Radial Bar Chart component to your project with the shadcn CLI. It lands in components/radial-bar-chart.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/radial-bar-chartOr copy the source by hand and install its dependencies:
npm install clsx tailwind-mergeProps
<RadialBarChart /> accepts 10 props, all optional. It also accepts the usual <div> attributes, like className, style, id and aria-*, and passes them to its root element.
| Prop | Type | Default |
|---|---|---|
| theme | "dark" | "light" | "dark" |
| title | string | "Sessions by hour" |
| subtitle | string | "Average weekday, local time" |
| values One value per slice, clockwise from the top (24 for hours of the day). | number[] | DEFAULT_VALUES |
| compare Optional comparison values (same length), drawn as faint outlines behind the bars; null hides them. | number[] | null | DEFAULT_COMPARE |
| labels Label for each slice; defaults to hours "00"–"23". | string[] | — |
| seriesLabels Names for the two series, used in the legend and tooltip. | [current: string, compare: string] | ["This week", "Last week"] |
| colors Bars blend from the first colour (quiet) to the second (busy). | [string, string] | — |
| size Diameter of the chart, in px (smaller when the card is narrow). | number | 380 |
| formatValue | (value: number) => string | (v) => Math.round(v).toLocaleString("en-US") |
- theme"dark" | "light"Default: "dark"
- titlestringDefault: "Sessions by hour"
- subtitlestringDefault: "Average weekday, local time"
- values
One value per slice, clockwise from the top (24 for hours of the day).
number[]Default: DEFAULT_VALUES - compare
Optional comparison values (same length), drawn as faint outlines behind the bars; null hides them.
number[] | nullDefault: DEFAULT_COMPARE - labels
Label for each slice; defaults to hours "00"–"23".
string[] - seriesLabels
Names for the two series, used in the legend and tooltip.
[current: string, compare: string]Default: ["This week", "Last week"] - colors
Bars blend from the first colour (quiet) to the second (busy).
[string, string] - size
Diameter of the chart, in px (smaller when the card is narrow).
numberDefault: 380 - formatValue(value: number) => stringDefault: (v) => Math.round(v).toLocaleString("en-US")
npm dependencies
Installed for you by the shadcn CLI.
Radial Bar Chart FAQ
- What data does it take?
- values is a list of numbers drawn clockwise from the top. With 24 values the labels default to hours; pass labels for anything else, such as months.
- What are the small ticks?
- compare draws a second series (last week by default) as a short tick across each bar at its value. seriesLabels names both series; pass compare={null} to hide it.
- Can I change the colours?
- colors takes the quiet and busy colours; each bar blends between them by its value. size sets the largest diameter.
- Is it accessible?
- The chart is focusable with a text summary of every slice; arrow keys move between slices and update the centre readout, Escape clears. With reduced motion the bars appear without growing.