Race bar chartPro

A ranking over time: bars overtake each other on springs, values count up, and a timeline you can play or scrub.

Live · keyboard ready

Revenue by product

Year to date, 2025

  • Furniture
  • Lighting
  • Textiles
  • Tableware

Revenue by product, year to date 2025
ItemJanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovemberDecember
Oak lounge chair$14K$30K$52K$86K$138K$208K$296K$400K$520K$658K$814K$992K
Linen throw$92K$170K$222K$256K$280K$296K$310K$326K$352K$400K$480K$598K
Mushroom lamp$66K$128K$186K$240K$291K$339K$385K$435K$492K$560K$638K$728K
Glass carafe$10K$22K$40K$70K$122K$206K$304K$394K$448K$474K$492K$522K
Stoneware cups$44K$86K$130K$171K$213K$253K$291K$331K$373K$418K$470K$540K
Stacked bowls$27K$53K$81K$110K$137K$165K$191K$218K$247K$277K$313K$360K
Ceramic lamp$18K$38K$59K$79K$101K$122K$144K$168K$194K$222K$253K$287K
Walnut sideboard$75K$138K$195K$246K$291K$330K$366K$399K$438K$483K$534K$588K
Striped pillow$10K$21K$34K$50K$67K$85K$104K$121K$137K$153K$171K$194K
Wool rug$40K$74K$102K$122K$137K$148K$157K$168K$186K$216K$256K$306K
  • Showing how the leaders of a ranking change across many periods.
  • A launch or recap moment where the motion itself is the point.
  • Letting people scrub to any period and read exact values.
  • Use line-chart when exact trends over time matter more than rank.
  • Use bar-chart for a single period's comparison.
  • Avoid for dashboards people glance at; autoplay competes with other content.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { RaceBarChart } from "@/registry/components/race-bar-chart/race-bar-chart"; const items = [  { id: "chair", label: "Oak lounge chair", group: "furniture" },  { id: "lamp", label: "Mushroom lamp", group: "lighting" },];const frames = [  { period: "January", values: { chair: 14000, lamp: 66000 } },  { period: "February", values: { chair: 30000, lamp: 128000 } },]; export function ProductRace() {  return <RaceBarChart items={items} frames={frames} groups={[{ id: "furniture", label: "Furniture" }, { id: "lighting", label: "Lighting" }]} label="Revenue by product" highlight="chair" />;}

RaceBarChart

A bar chart race: bars overtake each other on springs as values grow, numbers count continuously, the period rolls in large type, and a timeline plays, pauses, and scrubs through time.

PropTypeDefaultDescription
itemsRequired{ id: string; label: string; group?: string }[]–The things being ranked. A stable id keeps each bar's identity across frames.
framesRequired{ period: string; values: Record<string, number> }[]–One frame per period, in order. Missing ids count as zero.
labelRequiredstring–What is ranked. Names the chart for assistive technology.
groups{ id: string; label: string }[]–Names and order of the groups. The first four take the series hues and a legend appears; without groups every bar takes the first hue.
formatValue(value: number) => string–Formats values on bars, in the tooltip, and in the table. Defaults to a compact number.
formatTick(value: number) => string–Formats the value axis.
barsnumber8Bars shown at once. Items below the cut slide out of view.
framenumber–Controlled frame index. A new value glides the race there.
defaultFramenumber0Initial frame when uncontrolled.
onFrameChange(index: number) => void–Called when the shown period changes.
playingboolean–Controlled playback.
defaultPlayingbooleanfalseInitial playback when uncontrolled.
onPlayingChange(playing: boolean) => void–Called when playback starts or stops.
autoPlaybooleantrueStarts playing the first time the chart scrolls into view. Ignored with reduced motion.
frameDurationnumber1400Milliseconds per period while playing.
loopbooleanfalseRewinds to the first period after the last and keeps playing.
highlightstring–Item id whose name and value are emphasized, such as your own product.
classNamestring–Extra class on the root figure.
SpaceorEnter
Plays or pauses. At the end, replays from the start.
ArrowLeftorArrowRight
Steps one period back or forward; the race glides there.
ArrowUporArrowDown
Moves the reading through the bars by rank and shows the tooltip.
HomeorEnd
Jumps to the first or last period.
Escape
Clears the reading.
  • The plot is a focusable group with a description of its keys; the timeline is role="slider" with the period as aria-valuetext.
  • Stepping announces the period and the leader through a polite live region; reading a bar announces its name, rank, and value.
  • A visually hidden table lists every item's value for every period.
  • Group hue is never the only cue: every bar carries its name and value.
  • Time is continuous: values interpolate between periods, so bars grow smoothly and numbers count rather than jump.
  • Rank changes move each row on its own spring, so overtakes read as one continuous slide; bars entering the top set rise from below and fade in.
  • The drawn clock follows the requested time on a critically damped spring, so steps glide and a replay sweeps back through every period.
  • Axis ticks glide with the scale and crossfade when the step changes; the period label rolls in with a short blur.
  • Playback pauses while the chart is off screen. Reduced motion skips autoplay, steps periods without interpolation, and places bars immediately.
  • Below 400px names move inside the bars so bar length keeps its room; values sit past the name when a bar is short.
  • The tick count adapts to the plot width and the period label steps down a size on small screens.
  • The timeline is a 36px tall touch target and scrubs with a finger.
  • One requestAnimationFrame loop writes transforms, widths, and text straight to the DOM; React renders only on period changes.
  • The loop sleeps when paused and settled.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose it for a ranking that changes over time, told as a story: top products, cities, or accounts month by month.
  • Pass cumulative values (year to date) for a race that only grows, or raw values for a ranking that rises and falls.
  • Keep items to about 20 and bars to 6 to 10; the table carries the rest.
  • Colors come from the shared --series-1 to --series-4 tokens in foundation.css: series 1 is the accent itself and series 2 to 4 rotate its hue, validated all-pairs for color vision deficiency across every accent in light and dark. Override the tokens on any ancestor to rebrand.

The full library index for assistants is at /llms.txt.