Fade In On Scroll
Content that fades and rises into place as it enters the viewport.
6 frameworksIntermediate
An animated counter that eases up to its target value when scrolled into view.
<p class="text-4xl font-bold tabular-nums text-gray-900 dark:text-gray-100">
<span data-countup data-to="12500" data-decimals="0" data-prefix="$" data-suffix="+">$0+</span>
</p>
<script>
(function () {
var el = document.querySelector('[data-countup]');
if (!el) return;
var to = parseFloat(el.dataset.to || '0');
var decimals = parseInt(el.dataset.decimals || '0', 10);
var prefix = el.dataset.prefix || '';
var suffix = el.dataset.suffix || '';
function fmt(n) {
return (
prefix +
n.toLocaleString(undefined, {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
}) +
suffix
);
}
// Reduced motion / no observer: jump straight to the final value.
if (
!('IntersectionObserver' in window) ||
window.matchMedia('(prefers-reduced-motion: reduce)').matches
) {
el.textContent = fmt(to);
return;
}
function run() {
var start = 0;
function step(now) {
if (!start) start = now;
var p = Math.min((now - start) / 1600, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = fmt(to * eased);
if (p < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
run();
observer.disconnect();
});
},
{ threshold: 0.4 }
);
observer.observe(el);
})();
</script>| Prop | Type | Default | Description |
|---|---|---|---|
valuerequired | number | - | The metric's current value, pre-formatted. |
duration | number | 1600 | Animation length in seconds. |
decimals | number | 0 | Decimals |
prefix | string | '' | Prefix |
suffix | string | '' | Suffix |
Set `decimals`, `prefix` and `suffix` to format currency, percentages or plain stats. `duration` controls the count speed; reduced motion jumps to the final value.