KQ-1856 · PACE/BOARD
Pace Board
A display that swaps one value for the next with real motion: the new value arrives fast from the side on a spring between flick and recoil set by its overshoot, runs past its rest and on the way back is caught like a detent — locked, with a short judder — while the old one accelerates away stretching from its trailing edge. Both carry a horizontal motion blur in proportion to their own speed, an SVG blur in x only that is switched off at rest, so the faster a value moves the more it smears. Values cycle from a list or follow a live number, optionally swapping only the characters that changed; a cycling board pauses on hover, and with keyboard focus Space pauses and resumes it while Left, Right, Home and End step through it.
Gaugeworks · Ride telemetry
Built for teamsSpace pauses or resumes; Left and Right step through.
1,284 riders on course right now
teams · 1 of 4 · every 2.4 s
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/pace-board
Props
- values
- readonly string[]
- default —
- Words to cycle through, one at a time.
- value
- string | number
- default —
- A live value: every change swaps it in; numbers go through `format`. Wins over `values`.
- format
- (value: number) => string
- default grouped thousands
- Formats a number `value`.
- index / defaultIndex
- number
- default 0
- The shown entry of `values`, controlled or not.
- onIndexChange
- (index: number) => void
- default —
- Fires from the timer, key or click that moved it, with the new index.
- interval
- number
- default 2400
- Time each entry holds before the next swaps in, ms.
- blur
- number
- default 0.6
- Motion-blur strength, 0 (none) to 1 (a heavy smear at speed).
- overshoot
- number
- default 0.5
- How far a new value runs past its rest before it locks, and how hard it judders, 0 to 1.
- speed
- number
- default 1
- Spring speed, 0.5 (unhurried) to 2 (snappy).
- travel
- number
- default 0.9
- How far a new value comes from, in widths of its window.
- from
- "right" | "left" | "auto"
- default "right"
- The side new values arrive from; auto brings rising numbers from the right and falling ones from the left. Stepping back reverses it.
- swap
- "word" | "chars"
- default "word"
- Swap the whole value, or only the characters that changed, each in its own window.
- stagger
- number
- default 28
- Time between characters in chars mode, ms, starting on the side the motion comes from.
- trigger
- "mount" | "inView" | "manual"
- default "inView"
- When `values` start cycling: at mount, the first time it is seen, or never (keys, clicks and `index` only).
- paused
- boolean
- default false
- Stop cycling; live values still swap.
- onPausedChange
- (paused: boolean) => void
- default —
- Fires when Space pauses or resumes the cycle.
- progress
- boolean
- default false
- Draw a hairline under the value that fills until the next swap.
- reserve
- string
- default —
- A sample whose width is always kept, so a growing number never shifts the layout.
- align
- "start" | "center" | "end"
- default "start"
- Where the value sits in its kept width.
- as
- React.ElementType
- default "span"
- The element to render.
- label
- string
- default —
- Read before the value by assistive technology; names a cycling board.
- live
- "off" | "polite"
- default "off"
- Announce each new value politely; off by default so a cycling board never chatters.
- onSwap
- (text: string) => void
- default —
- Fires as a swap starts, with the new text.
- className
- string
- default —
- Font size, weight and colour inherit; style it like text.
| Prop | Type | Default | Description |
|---|---|---|---|
| values | readonly string[] | — | Words to cycle through, one at a time. |
| value | string | number | — | A live value: every change swaps it in; numbers go through `format`. Wins over `values`. |
| format | (value: number) => string | grouped thousands | Formats a number `value`. |
| index / defaultIndex | number | 0 | The shown entry of `values`, controlled or not. |
| onIndexChange | (index: number) => void | — | Fires from the timer, key or click that moved it, with the new index. |
| interval | number | 2400 | Time each entry holds before the next swaps in, ms. |
| blur | number | 0.6 | Motion-blur strength, 0 (none) to 1 (a heavy smear at speed). |
| overshoot | number | 0.5 | How far a new value runs past its rest before it locks, and how hard it judders, 0 to 1. |
| speed | number | 1 | Spring speed, 0.5 (unhurried) to 2 (snappy). |
| travel | number | 0.9 | How far a new value comes from, in widths of its window. |
| from | "right" | "left" | "auto" | "right" | The side new values arrive from; auto brings rising numbers from the right and falling ones from the left. Stepping back reverses it. |
| swap | "word" | "chars" | "word" | Swap the whole value, or only the characters that changed, each in its own window. |
| stagger | number | 28 | Time between characters in chars mode, ms, starting on the side the motion comes from. |
| trigger | "mount" | "inView" | "manual" | "inView" | When `values` start cycling: at mount, the first time it is seen, or never (keys, clicks and `index` only). |
| paused | boolean | false | Stop cycling; live values still swap. |
| onPausedChange | (paused: boolean) => void | — | Fires when Space pauses or resumes the cycle. |
| progress | boolean | false | Draw a hairline under the value that fills until the next swap. |
| reserve | string | — | A sample whose width is always kept, so a growing number never shifts the layout. |
| align | "start" | "center" | "end" | "start" | Where the value sits in its kept width. |
| as | React.ElementType | "span" | The element to render. |
| label | string | — | Read before the value by assistive technology; names a cycling board. |
| live | "off" | "polite" | "off" | Announce each new value politely; off by default so a cycling board never chatters. |
| onSwap | (text: string) => void | — | Fires as a swap starts, with the new text. |
| className | string | — | Font size, weight and colour inherit; style it like text. |