ComponentsNumbers
Odometer
A mechanical wheel that spins past every digit.
Installation
$ npx shadcn@latest add @textlab/odometerNeeds @textlab in your components.json. Setup takes a minute.
Usage
usage.tsx
import { Odometer } from "@/components/textlab/odometer/odometer";
<Odometer value={miles} digits={6} framed />Variants
mechanicalsmoothProps
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | number | – | A whole, non-negative number. |
| variant | "mechanical" | "smooth" | "mechanical" | mechanical clicks a wheel over only when its neighbour passes 9; smooth spins every wheel continuously. |
| digits | number | 1 | Minimum number of wheels, padded with zeros. |
| duration | number | 1.6 | Seconds to travel to the new value. |
| ease | EaseName | [number, number, number, number] | "standard" | Easing token or cubic bezier. |
| framed | boolean | false | Thin separators between wheels. |
| locale | string | "en-US" | Used for the screen-reader label. |
| as | ElementType | "span" | Rendered element. |
| reducedMotion | "user" | "always" | "never" | "user" | user follows the OS setting; always shows the still version. |
| className | string | – | Merged onto the root. |
When to use it
Reach for it
- Visitor counts, mileage and totals with a physical feel.
- Big jumps where you want people to sense the distance travelled.
Skip it
- Currency with decimals; use rolling-number or price-ticker.
- Negative numbers.
Accessibility and motion
Accessibility
- Screen readers get the formatted number once; the wheels are aria-hidden.
Motion
- One motion value drives every wheel, so they always agree.
- Edges are masked so wheels read as curved drums.
Reduced motion. The new value appears immediately.
Performance
- One animation per change; wheel positions are derived transforms.