Instructions
count-up attribute referenced below must stay intact for the code to find the right elements.Count-up statistics
This template includes a global script that makes any number count up from zero when it scrolls into view, with a soft blur that resolves as the number settles into place. It's used for the proof stats throughout the template. Each counter runs once — the first time it enters the viewport.
How it works (high level)
The script finds every element carrying the count-up attribute. For each one it reads the text you've typed in as the target value — a small helper strips out formatting and works out whether the last separator is a decimal point or a thousands separator, so both 1,200 and 1.200 are read correctly. It also captures any non-numeric suffix (like +, %, k, M). When the element reaches 80% down the screen, a GSAP timeline runs once: the element blurs from 6px down to sharp, while a counter animates from zero to the target. On each frame the number is snapped to a whole value, re-formatted with thousands separators, and the suffix is re-attached.
How to use it
- Select the text element that holds the number.
- Add the custom attribute
count-upto it (attribute namecount-up, no value needed). - Type the final number straight into the element in the Designer — that typed value is the target the counter climbs to.
- Any suffix is kept automatically:
250+,98%,1.2k,40Mall work — just type them into the element.
Where the code lives
The script is added once, globally:
- Project Settings → Custom Code
- Place it in the Footer (Before
</body>) section
The code
<script>
gsap.registerPlugin(ScrollTrigger);
function parseFormattedNumber(str) {
var num = str.replace(/[^\d.,]/g, "");
var decimal = num.match(/[.,](\d{1,2})$/);
return parseFloat(decimal
? num.slice(0, decimal.index).replace(/[.,]/g, "") + "." + decimal[1]
: num.replace(/[.,]/g, "")
);
}
gsap.utils.toArray("[count-up]").forEach(function(el) {
var raw = el.textContent.trim();
var target = parseFormattedNumber(raw);
var suffix = raw.replace(/[\d,.]/g, "");
var counter = { val: 0 };
gsap.timeline({
scrollTrigger: { trigger: el, start: "top 80%", once: true }
})
.fromTo(el, { filter: "blur(6px)" }, { filter: "blur(0px)", duration: 2.25, ease: "power2.out" }, 0)
.to(counter, {
val: target,
duration: 2,
ease: "power2.out",
onUpdate: function() {
el.textContent = gsap.utils.snap(1, counter.val).toLocaleString() + suffix;
}
}, 0);
});
</script>Want to tweak it (optional)
- Count speed: change
duration: 2on the counter (higher = slower count). - Blur amount and speed: change
blur(6px)for a stronger/softer start, andduration: 2.25for how long it takes to sharpen. - Trigger point: change
start: "top 80%"— how far down the screen the element must scroll before it fires.
Important notes
- This requires GSAP + ScrollTrigger to be loaded on the site.
- Each counter fires once, the first time it scrolls into view.
- Whole numbers only — the count snaps to integers, so decimals in the target get rounded. For a decimal stat, set it as static text without the attribute.
- Only a suffix is preserved. A leading symbol like
$1,200gets pushed to the end (1,200$). For currency, put the symbol in a separate element next to the number, or use it as a suffix. - Keep the
count-upattribute on any element you want animated.



















