Data✨ Premium

Stat Cards

Three number cards that grow one after the other when the block reaches the screen, while each value counts up to its target.

JSCards

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Data has 28 effects, including 1 free. Explore the category →

3 usage examples

Crowdfunding campaign counters — under a brewery's video — Stat Cards example 1

① Crowdfunding campaign counters — under a brewery's video

WhenBelow the pitch video, three cards give the state of the campaign: €18,240 raised, 412 backers, 9 days left. They appear and count when the visitor scrolls down to them, above the goal bar.
WhyOn a fundraising page, these three numbers decide the pledge: watching them climb as they are discovered gives them momentum, where they would have gone unnoticed under the video.
SettingsFull-width transparent root (--stcd-bg:transparent, --stcd-height:0px, --stcd-max:none), gradient #b45309→#dc2626, white cards --stcd-card:#fff, border #f0dcb4, values enlarged to 1.65rem by the scene. data-prefix="€" on the first one in English. The scene scrolls the page down to the block half a second after it shows.
Summary after deleting duplicates — screen of a photo gallery app — Stat Cards example 2

② Summary after deleting duplicates — screen of a photo gallery app

WhenThe app found 412 duplicates; the user taps "Delete duplicates" and the final screen opens: 412 photos, 3.8 GB freed, 64% free space, cards popping one after the other.
WhyAfter an action nobody sees (files disappearing), a summary in figures reassures and shows the gain; the animation marks the end of the job.
SettingsTight cards for a phone screen: .stcd-card at a 60 px base, values at 1.05rem, gradient #0284c7→#7c3aed, data-target="3.8" data-suffix=" GB" and data-suffix="%". The summary screen is hidden until the tap, the cards start as they appear.
A player's statistics in the popover of their username — ranking on a chess site — Stat Cards example 3

③ A player's statistics in the popover of their username — ranking on a chess site

WhenIn the weekly blitz ranking, a click on a username opens a popover with games, wins and current streak. A click on another player moves the popover and the three values count towards theirs.
WhyComparing players by hopping from one to the next speaks more when the numbers glide: you see at once who played or won more than the previous one.
Settings256 px popover: cards at a 60 px base, values at 1.15rem, gold gradient #fde68a→#f59e0b, background rgba(253,230,138,.06). Clicking a username writes the player's three values into the data-target attributes; in the capture, a click elsewhere moves to the next player.

How it works

Each .stcd-card holds a .stcd-value and a .stcd-label. The target lives in data-target (decimals with a dot: 2.4), the unit in data-prefix or data-suffix ("K", "%", " €"). The text written in the HTML stands as the final value until the script runs.

On start, the script hides the cards and resets the values to 0. When the block is half visible (IntersectionObserver, only once), the cards grow from 80% to 100% with a slight bounce (0.6 s, 0.1 s apart) and each value counts from 0 to its target over 2 s, slowing down at the end. The format follows the page language: "2.4K" and "89%" in English with the English HTML provided, "2,4 k" and "89 %" in French.

Changing data-target (or the unit) later counts again, from the displayed value to the new one: handy for a dashboard that updates or a popover that changes subject. Each .fx-0229-root lives on its own, nothing is declared on window.

Accessibility

  • Screen readers: the moving value is hidden (aria-hidden) and the script places a hidden text right after it with the final value and its unit. Users hear "2.4K Sales, 89% Rate, 156 Clients". After a change of data-target, that text is updated at once.
  • Reduced motion: under prefers-reduced-motion: reduce, the cards are visible without growing and the final values are set straight away; a new data-target also shows without counting.
  • Without script: the cards stay visible with the HTML text; only the script hides them before they appear.
  • Labels: the unit sits with the value and the word in the label ("89%" then "Rate"), which reads in the right order.

Browser compatibility

Dependency-free JavaScript (about 3 KB), CSS animation and CSS variables. Measured on 08/11/2026 in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): cards and count on appearance, a block further down waiting for the scroll, a new data-target on the 2nd copy without touching the 1st, 390 px, reduced motion, French and English formats, no error. Versions taken from @mdn/browser-compat-data: IntersectionObserver sets the minimum.

Chrome 51+✓ Full (measured)
Firefox 55+✓ Full (measured)
Safari 12.1+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
iOS Safari 12.2+✓ Not checked on a real device
Android Chrome 51+✓ Full (Chromium engine)

Without IntersectionObserver, the cards and final values show at once. Without JavaScript, the cards display the text written in the HTML.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0229-root">
  <div class="stcd-cards">
    <div class="stcd-card">
      <div class="stcd-value" data-target="2.4" data-suffix="K">2.4K</div>
      <div class="stcd-label">Sales</div>
    </div>
    <div class="stcd-card">…</div>
    <div class="stcd-card">…</div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Value (HTML — data-target on .stcd-value) 2.4 · 89 · 156 Count target, decimals written with a dot. Changing it later in JavaScript counts again from the displayed value.
Unit (HTML — data-prefix and data-suffix) "K" and "%" as suffixes on the first two Text glued before or after the number: data-prefix="$", data-suffix=" €". Put the space inside the attribute if your language wants one.
Duration (HTML — data-duration on .stcd-value) 2000 (milliseconds) Length of the count, set value by value.
Number of cards (HTML) 3 Add or remove .stcd-card elements; they wrap below the --stcd-max width. The 0.1 s offset is set for the 2nd and 3rd cards.
Colours (CSS — --stcd-from, --stcd-to, --stcd-card, --stcd-border, --stcd-muted) #6366f1 → #d946ef · indigo at 10% · indigo at 30% · white at 50% Value gradient, card background and border, label colour.
Block width (CSS — --stcd-max) 360px Maximum width of the row of cards; none to fill the whole column.
Background and height (CSS — --stcd-bg, --stcd-height) #0a0a0f · 300px Inside a page: --stcd-bg:transparent; --stcd-height:0px.

FAQ

Write the new value into the attribute: card.querySelector('.stcd-value').setAttribute('data-target', '3.1'). The script notices it and counts from the old one. The text read by screen readers changes at the same time.
No, the entrance plays once, on first appearance. Only the values count again when data-target changes.
The decimal separator comes from the page language (lang); the unit comes from your data-suffix. The French HTML provided uses data-suffix=" k" and " %" with a space, as French usage wants.