Number Ticker
A number that counts up to its value when it scrolls into view, and re-animates whenever the value changes. Built for stats sections and live dashboards. Requires the PetalNumberTicker hook from the petal_components JS bundle. The final value is rendered server-side, so the number is correct without JavaScript.
Basic number ticker
Give it a unique id (required) and a value. The counter runs from start_value (0 by default) to value when the element enters the viewport.
<.number_ticker id="basic-number-ticker-example" value={5200} class="text-4xl font-bold" />
Formatting
Use prefix and suffix to wrap the number, and decimal_places to set the precision shown while counting. Formatting runs through Intl.NumberFormat, so thousands separators and decimal marks follow the browser locale by default. Pass locale to pin a specific one, like de-DE.
<.number_ticker id="format-prefix-example" value={48500} prefix="$" class="text-3xl font-bold" />
<.number_ticker
id="format-suffix-example"
value={99.95}
suffix="%"
decimal_places={2}
class="text-3xl font-bold"
/>
<.number_ticker
id="format-locale-example"
value={1_234_567.89}
decimal_places={2}
locale="de-DE"
class="text-3xl font-bold"
/>
Live updates
Bind value to an assign and the ticker re-animates whenever it changes, counting from the previous value to the new one instead of restarting at start_value. Click the button to see it.
<.number_ticker id="live-update-example" value={@stars} class="text-4xl font-bold" />
<.button size="sm" variant="outline" label="Update value" phx-click="randomize_stars" />
# In your LiveView:
# def handle_event("randomize_stars", _, socket) do
# {:noreply, assign(socket, :stars, Enum.random(3_000..9_999))}
# end
Stats row
The classic marketing strip: a row of tickers with small labels underneath. Each ticker needs its own unique id.
<div class="flex flex-wrap justify-center gap-12 py-4 text-center">
<div>
<.number_ticker id="stats-stars-example" value={6100} suffix="+" class="text-4xl font-bold" />
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400">GitHub stars</div>
</div>
<div>
<.number_ticker id="stats-mrr-example" value={28400} prefix="$" class="text-4xl font-bold" />
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400">MRR</div>
</div>
<div>
<.number_ticker
id="stats-uptime-example"
value={99.99}
decimal_places={2}
suffix="%"
class="text-4xl font-bold"
/>
<div class="mt-1 text-sm text-gray-500 dark:text-gray-400">Uptime</div>
</div>
</div>
Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
extra classes (set font size/weight here) |
decimal_places
|
integer |
0
|
decimal places to show while counting |
duration
|
integer |
1500
|
animation length in milliseconds |
id*
|
string |
||
locale
|
string |
nil
|
BCP 47 locale for number formatting (e.g. "de-DE"); defaults to the browser locale |
prefix
|
string |
nil
|
e.g. "$" |
rest
|
global |
||
start_value
|
any |
0
|
where the first animation counts from |
suffix
|
string |
nil
|
e.g. "+" or "%" |
value*
|
any |
the target number (integer or float) |