WebberUI

CJK Number Roller

Numbers rolling between three forms — lowercase Chinese numerals, formal (financial) Chinese numerals, and Arabic digits — with automatic conversion to the formal amount form.

Numbers roll between three formats: Arabic digits, lowercase Chinese numerals, and formal Chinese amount numerals. A built-in converter turns 123456 into 「十二萬三千四百五十六」 or 「壹拾貳萬參仟肆佰伍拾陸元整」. When the value changes, each position scrolls up or down individually (odometer style — unit characters that did not change stay put), and switching formats cross-fades the whole set.

Loading preview…
npx shadcn@latest add https://webberui.com/r/cjk-number-roller.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

10500
<CjkNumberRoller />

Installation

npx shadcn@latest add https://webberui.com/r/cjk-number-roller.json

Or, once registries are configured in components.json, install it as @webberui/cjk-number-roller.

Usage

import {
  CjkNumberRoller,
  numberToChinese,
} from "@/components/ui/cjk-number-roller";

<CjkNumberRoller value={123456} format="arabic" prefix="NT$" />
<CjkNumberRoller value={123456} format="lower" />
<CjkNumberRoller value={123456} format="upper" className="text-4xl font-semibold" />

// The converter can also be called on its own
numberToChinese(123456, "lower"); // 十二萬三千四百五十六
numberToChinese(123456, "upper"); // 壹拾貳萬參仟肆佰伍拾陸

Props

PropTypeDefaultDescription
valuenumberThe value to display; it is rounded and clamped to 0 ~ Number.MAX_SAFE_INTEGER
formatCjkNumberFormat"arabic"Display format: arabic (Arabic digits with thousands separators), lower (lowercase Chinese numerals), upper (formal amount numerals)
prefixstringPrefix before the number (such as NT$), shown at a smaller size on the left
animatebooleantrueWhether the rolling animation is enabled
currencySuffixbooleantrueWhether the upper format automatically appends 「元整」
classNamestringForwarded to the outer container

There is also a named export for the pure function numberToChinese(value, style) (with style being "lower" or "upper"): gaps between groups get a 「零」 as convention dictates (10500 → 一萬零五百), and a leading 「一十」 in the lowercase form is shortened to 「十」. The unit table goes up to 「兆」, which already covers the JS safe integer range.

Accessibility

  • The fully formatted result is exposed sr-only for screen readers, while the per-position animated characters are hidden from assistive technology (aria-hidden)
  • When the user has "reduce motion" enabled at the system level, or animate is set to false, static text is rendered directly and no animation is mounted at all
  • The animation only starts after the client mounts, so the first SSR output matches the client and there is no hydration difference

On this page