Brik Design System
Components

CountUp

A number that counts up to its final value when it scrolls into view.

CountUp renders a number that counts up to its final value the first time it scrolls into view. The final value is the element's real text, so with JavaScript off, under prefers-reduced-motion: reduce, or for a value with no number it renders as a plain static number — the sweep is a pure enhancement, never a gate. Duration and easing are token-backed (--duration-xl / --ease-out), and tabular-nums holds the width steady so the surrounding layout does not jitter as the digits change.

It has one visual appearance — the only input is the value it counts to, and it parses the number out of whatever string it wraps (4,800+, 98%, $2M), re-appending the prefix, suffix, and thousands grouping while counting.

CountUp

Use when: A proof-point number that should animate up as the reader reaches it — a stat bar, a metric callout. The motion draws the eye to the figure.

Don't: A static count badge or a live-updating tally — that's Counter.

<CountUp>4,800+</CountUp>

Counter

Use when: A small static numeric indicator with tone colors — an unread count, a quantity chip. No animation.

Don't: The number should sweep up into view — that's CountUp.

<Counter value={12} />

Use it for

  • A proof-point stat bar (the first adopter is the stats_bar blueprint via contentMotion: count-up)
  • A single metric callout where the count-up motion reinforces the figure

Blueprints never place CountUp directly — a block sets contentMotion: count-up on its section and the shared BlockContentMotion dispatcher wraps each number.

Import

import { CountUp } from '@brikdesigns/bds';

Default

4,800+

The value shapes it handles — bare integer, grouped thousands, percentage, unit suffix, currency prefix — are all the same component reading a different string:

124,800+98%24h$2M

Accessibility

  • The count fires once, when at least half the number is in view. Under prefers-reduced-motion: reduce it never runs — the static final number is already the DOM text, so there is no un-gated motion path.
  • The number is content, not decoration. The sweep only transiently changes the text, so assistive tech announces the final value.
  • CountUp provides no accessible name of its own; it is a number inside surrounding content (a stat's caption, a section heading) that names it.

CSS Override API

VariableDefaultPurpose
--bds-count-up-durationvar(--bds-duration-xl) (500ms)Length of the count sweep
--bds-count-up-easevar(--bds-ease-out)Easing curve the sweep follows

API

PropTypeDefault
childrenReactNode— (required — the final value; the number counts up to it)

Inherits all native <span> attributes (className, style, data-*, …).

On this page

💬