Rolling Number
v0.0.10
mix mishka.ui.gen.headless rolling_number
Overview of the Phoenix and LiveView Headless Rolling Number Component
The Mishka Chelekom Headless Rolling Number animates a number to its value in Phoenix and LiveView. It renders one <span> that carries the RollingNumber hook. On mount the hook counts up from 0 to value, and whenever LiveView renders a different value it animates from the number on screen to the new one. The motion uses requestAnimationFrame with an ease-out curve.
The component ships no styling. The span takes class, so size, weight and tabular-nums are yours to choose. duration is the animation time in milliseconds and locale sets the digit grouping. With prefers-reduced-motion: reduce the number is shown at once.
Base UI Rolling Number example - numbers that roll up on mount (Phoenix headless)
The first number uses the default 800 ms. The second takes 1400 ms and is grouped by the browser, so it reads as 1,000,000 in an English locale.
Base UI Rolling Number example - numbers that roll up on mount (Phoenix headless)
<div class="flex gap-8 text-neutral-900 dark:text-white">
<.rolling_number id="baseui-rolling-number-1" value={2048} class="text-3xl font-bold tabular-nums" />
<.rolling_number
id="baseui-rolling-number-2"
value={1_000_000}
duration={1400}
class="text-3xl font-bold tabular-nums"
/>
</div>Updating the value from the server
Assign a new integer and render again. The hook sees the new value in its updated callback and rolls from the current number to it. The element needs a stable id, because LiveView matches the hook to the element by it.
<div class="flex items-center gap-4">
<.rolling_number id="visitors" value={@visitors} class="text-3xl font-bold tabular-nums" />
<button type="button" phx-click="randomize">Randomize</button>
</div>def handle_event("randomize", _params, socket) do
{:noreply, assign(socket, :visitors, Enum.random(100..999_999))}
endDuration and locale
duration defaults to 800. locale is a BCP 47 language tag, such as de-DE, and the hook passes it to the browser's number formatting to group the digits. Without it the browser uses its own locale.
<.rolling_number id="revenue" value={@revenue} locale="de-DE" duration={1200} />Parts & data attributes
The component has a single part. It carries the structural class chelekom-rolling-number and the values the hook reads.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | root | data-value, data-duration, data-locale | The span that carries the RollingNumber hook. Its text is the animated number, and the server renders the plain value as the first text. |
Accessibility
There is no formal WAI-ARIA APG pattern for an animated number. The span holds the final number as text from the first render, so with JavaScript off, or before the hook mounts, the number is still on the page. With prefers-reduced-motion: reduce the hook skips the animation and writes the final number straight away.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | Yes | Unique id (carries the RollingNumber hook) |
value
|
integer
| — | — | Yes | The target number |
duration
|
integer
|
800
| — | No | Animation duration in ms |
locale
|
string
| — | — | No | BCP-47 locale for thousands grouping |
class
|
any
| — | — | No | Extra classes |
rest
|
global
| — | — | No | — |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
rolling_number
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless rolling_number