Motion
CountUp: a number that counts up to its value on the client, while the server renders the final value in NumberValue's element. Tabular digits that keep their width, 0 ms under reduced motion, and nothing announced while it counts. Also useCountUp, for an element of your own.
Import
import { CountUp } from '@nizivo/react/motion';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css and @nizivo/react/css/number-value.css
import '@nizivo/react/css/motion.css';Static or interactive
Client. CountUp is a client module (count-up.client.tsx), the one client part of the
dashboard set, so it always ships its code. Its server HTML is the final formatted value in
NumberValue's <data> element, so the number is right before hydration and without JavaScript; the
client only animates it. For a number that does not count, use
NumberValue, which ships nothing. How to
choose.
When it counts
It counts with requestAnimationFrame, only while the element is in the viewport. An element
mounted on the client counts from from (default 0). An element that was already on screen when
the server HTML hydrated keeps its number: its reader has seen it. An element off screen counts when
it first comes into view. A new value counts from the number on screen when the element is in
view, and shows at once when it is not.
The duration is --nz-duration-count-up (900 ms), read from the element; a duration prop in
milliseconds replaces it. Under prefers-reduced-motion: reduce or data-nz-motion="reduce" the
token is 0 ms and the value shows at once, whatever duration says
(Motion). The curve is cubic-bezier(0, 0, 0, 1), the same curve as
--nz-easing-enter, which Figma 04 proposed for count-up; it is written into the code and the token is
not read, so overriding the token does not change it. Figma defines no easing for count-up.
Accessibility
The counting digits are aria-hidden; a visually hidden copy beside them holds the final value,
which is what assistive technology reads. There is no live region, so nothing is announced while it
counts or when value changes. While counting, the digits keep the final string's width, so nothing
around them moves.
The Figma 04 notes proposed a separate @nizivo/motion package for this; the plan put it at the
@nizivo/react/motion subpath instead (ARCHITECTURE.md §13.4).
Examples
Count Up
The server renders each final value; the client counts it up once it is in view.
import type { JSX } from 'react';
import { CountUp } from '@nizivo/react/motion';
export function CountUpExample(): JSX.Element {
return (
<div>
<CountUp
value={48290}
format={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }}
/>
<CountUp value={1284} />
<CountUp value={0.124} format={{ style: 'percent', maximumFractionDigits: 1 }} />
{/* Starts at 1,000 instead of 0, in German grouping */}
<CountUp value={12500} from={1000} locale="de-DE" />
</div>
);
}
Props
NumberValue's <data> with the final value, counted up on the client. A client leaf: under RSC it is the one dashboard part that ships JavaScript (§17.2).
Client component Renders data-slot="count-up" with the class nz-count-up. Props: CountUpProps. Source: src/motion/count-up.client.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
duration | number | – | Milliseconds. The default reads From |
format | Intl.NumberFormatOptions | {} |
From |
from | number | 0 | Where the first count starts. Later counts start from the number on screen. From |
locale | string | 'en-US' | BCP 47 tag for the number. From |
render | RenderProp<CountUpState> | – | |
valuerequired | number | – |
- Also takes every attribute of
<data>exceptchildren,value. (Omit<ComponentPropsWithRef<"data">, "children" | "value">)
render takes an element, or, in client code, a function of the props and this state (CountUpState):
| Name | Type | Default | Description |
|---|---|---|---|
textrequired | string | – | The final formatted text, which the server renders and assistive tech reads. |
valuerequired | number | – |
Other exports
CountUpOptionstypeimport type { CountUpOptions } from '@nizivo/react/motion'Name Type Default Description durationnumber– Milliseconds. The default reads
--nz-duration-count-upfrom the element (900 ms). Under reduced motion that token is 0 ms and the value is shown at once, whatever this says.formatIntl.NumberFormatOptions{}Intl.NumberFormatoptions, as NumberValue takes them.fromnumber0Where the first count starts. Later counts start from the number on screen.
localestring'en-US'BCP 47 tag for the number.
CountUpPropstypeimport type { CountUpProps } from '@nizivo/react/motion'The props of
CountUp, listed above.CountUpStatetypeimport type { CountUpState } from '@nizivo/react/motion'NumberValue's state: the final value and its formatted text.
The render state of
CountUp, listed above.useCountUphookimport { useCountUp } from '@nizivo/react/motion'Counts the text of
ref's element up tovalue, formatted withformatNumber(so every frame reads like the server's text). Render the final formatted value in that element yourself; the hook only writes frames and gives the element the final string's width while it counts (make itinline-block). Keep itaria-hiddenand put the final value in visually hidden text beside it.function useCountUp(ref: RefObject<HTMLElement | null>, value: number, options?: CountUpOptions): void
Data attributes and slots
Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.
| Slot | Rendered by | Data attributes |
|---|---|---|
count-up.nz-count-up | CountUproot (takes render) | none |
count-up-value.nz-count-up-value | CountUpinner element (CSS only) | none |
CSS hooks
Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.
This stylesheet reads no public hook.
Layers: nz.components. Classes: .nz-count-up-label, .nz-count-up-value.
Accessibility
Nothing in this component takes focus or keyboard input.
Keyboard
None.
Figma
Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.
- Canonical: none
- Ghost masters: none
MobileTopBar
The bar above the page below 640 px, with the store's mark or a back link, the page's name, and icon buttons for search and notifications.
NativeSelect
The browser's own select, styled like the Select trigger. Server-safe with no client code; use it where the native picker is the better choice, such as on phones or in Server Component forms.