Skip to main content
RollingNumber
@coinbase/cds-web@8.34.1
A numeric display that animates value changes with rolling digits.
Import
import { RollingNumber } from '@coinbase/cds-web/numbers/RollingNumber'
SourceView source codeStorybookView Storybook
View as Markdown

Basic Example

RollingNumber displays changing numeric values with a smooth per-digit roll animation and optional color pulse. It supports full Intl.NumberFormat options, custom typography, ReactNode prefixes/suffixes, and accessibility.

Pass a number in the value prop. Use the format prop for Intl formatting (currency, percent, grouping, compact) instead of pre-formatting the string yourself.

Loading...

Example Use Case

Loading...

Formatting

Use format prop for currency, percent, grouping, and compact notation formatting. The format prop takes in Intl.NumberFormat options.

Loading...

Typography

RollingNumber forwards all Text props, but only character-level typographic props (e.g., font, fontFamily, fontSize, fontWeight, lineHeight, tabularNumbers, color) are meaningful for its per-digit rendering. Layout/container props may have no effect—use them judiciously.

Loading...
Alignment

Keep tabularNumbers enabled (default) to avoid horizontal width shifting as digits change.

Color and Transition

Customize color and motion. Configure y to control the digit roll, and color for the pulse.

transition prop

  • Type: { y?: Transition; color?: Transition } (framer-motion Transition)
  • Optional type: 'tween' | 'spring' | 'inertia'; defaults to 'tween' if not provided
  • Default: { y: { duration: durations.moderate3 / 1000, ease: curves.global }, color: { duration: durations.slow4 / 1000, ease: curves.global } }
Loading...

Digit Transition Variants

RollingNumber supports two digit transition styles via the digitTransitionVariant prop:

  • 'every' (default): Rolls through every intermediate digit (e.g., 1→2→3→...→9).
  • 'single': Rolls directly to the new digit without showing intermediates. Direction (up/down) is based on the total value change.
Loading...

Variant comparison

Loading...
Direction-aware animation

The single variant determines scroll direction based on the total value change, not individual digit changes. When the value increases, digits roll up (new digits enter from below). When the value decreases, digits roll down (new digits enter from above). This matches the behavior of the color pulse feature.

Prefix and Suffix

Attach text or React nodes before/after the number to create rich compositions. If the prefix/suffix is a string, it will pulse color together with the main number.

Loading...
Loading...
Accessibility

When using React nodes for prefix/suffix, provide an accessibilityLabel or use accessibilityLabelPrefix/accessibilityLabelSuffix so screen readers announce a descriptive string.

Style Overrides

Customize the look of each logical section (i18nPrefix, integer, fraction, i18nSuffix, prefix, suffix).

Loading...

Subscript Notation for Tiny Decimals

Enable enableSubscriptNotation to compactly represent leading zeros in the fractional part.

Loading...

User-Provided Formatted Value

You can also provide formattedValue, and the component will render formattedValue directly instead of using the internal formatter. The numeric value is still required to drive animations and color pulse.

Loading...
Accessibility and formattedValue

When you provide formattedValue, the accessibilityLabel will default to your formattedValue. However, what’s rendered on screen is not always ideal for accessibility. For example, the subscript notation '0₉' may be announced as '09'. Provide your own accessibilityLabel as needed.

Patterns & Recipes

Practical demos combining formatting, animation, and interactivity.

Counter

Loading...

Countdown

Loading...

Live Auction

Loading...

Social Media Statistics

Loading...

Anatomy & Customization

RollingNumber is composed of small, swappable subcomponents and exposes granular className/style hooks for each section of the number. Use these to customize structure and styling or to plug in your own components.

Subcomponents

  • RollingNumberMaskComponent: Component used to mask the animated digit content.
  • RollingNumberAffixSectionComponent: Component used to render ReactNode prefix / suffix props.
  • RollingNumberValueSectionComponent: Component used to render the four Intl.NumberFormat sections (i18nPrefix, integer, fraction, i18nSuffix).
  • RollingNumberDigitComponent: Component used to render the per-digit roll animation.
  • RollingNumberSymbolComponent: Component used to render non-digit symbols (group separators, decimal, literals, etc.).

You can replace any of these with your own components via props:

<RollingNumber
RollingNumberMaskComponent={MyMask}
RollingNumberAffixSectionComponent={MyAffixSection}
RollingNumberValueSectionComponent={MyValueSection}
RollingNumberDigitComponent={MyDigit}
RollingNumberSymbolComponent={MySymbol}
value={1234.56}
format={{ style: 'currency', currency: 'USD' }}
/>

Class name overrides

Use classNames to target specific parts for CSS styling (Linaria or your own classes):

  • root: Outer container (Text root)
  • visibleContent: Motion-wrapped span containing the visible number (color animation lives here)
  • formattedValueSection: Container around the four i18n sections
  • i18nPrefix: Section generated by Intl.NumberFormat before the number
  • integer: Integer part of the number
  • fraction: Fractional part of the number
  • i18nSuffix: Section generated by Intl.NumberFormat after the number
  • prefix: Wrapper around your prefix prop
  • suffix: Wrapper around your suffix prop
  • text: Text element used for digits, separators, prefix, and suffix

Style overrides

Use styles to inline style specific parts:

  • root, visibleContent, formattedValueSection, i18nPrefix, integer, fraction, i18nSuffix, prefix, suffix, text

styles.text applies to the shared Text component that renders digits, symbols, prefix, and suffix.

Structure diagrams

High-level anatomy of RollingNumber and its sections:

RollingNumber (root: Text)
├── screenReaderOnly <span aria-live> (hidden a11y text)
└── <m.span> (visibleContent)
├── AffixSection (prefix) ← your ReactNode prefix
├── HStack (formattedValueSection)
│ ├── ValueSection (i18nPrefix)
│ ├── ValueSection (integer)
│ ├── ValueSection (fraction)
│ └── ValueSection (i18nSuffix)
└── AffixSection (suffix) ← your ReactNode suffix

Per-digit rendering inside a ValueSection:

ValueSection
├── Symbol(s) (e.g., currency, group, decimal)
└── Digit(s)
└── Mask
└── DigitContainer (animated)
├── non-active digits above (positioned)
├── active digit (centered)
└── non-active digits below (positioned)

Is this page useful?

Coinbase Design is an open-source, adaptable system of guidelines, components, and tools that aid the best practices of user interface design for crypto products.