JavaScript Document scroll Event

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Document event
Baseline Widely available

What You’ll Learn

The Document scroll event fires when the document view has been scrolled. Learn how to read window.scrollY, use document.onscroll, throttle handlers the MDN way with setTimeout, and when to prefer IntersectionObserver or scrollend—with five try-it labs.

01

Kind

Document event

02

Type

Event

03

Fires when

Document view scrolls

04

Position

window.scrollY

05

Tip

Throttle heavy work

06

Status

Baseline · Widely available

Introduction

When the user scrolls the page (or you call APIs that move the document view), the browser fires a scroll event on the Document. That is the signal for sticky headers, progress bars, “back to top” buttons, and parallax-style UI.

Scroll is busy: handlers can run many times per second. MDN warns that expensive DOM work inside every scroll callback can cause jank. Keep the listener light, and throttle work that must update the UI.

💡
Beginner tip

Document scroll is for the page view. If a <div> has its own scrollbar (overflow: auto), listen on that Element instead. To know when scrolling finished, look at scrollend.

Understanding Document scroll

A standard Document event that answers: “Did the document view just scroll?”

  • Fires when the document view has been scrolled (MDN).
  • Event type — a generic Event.
  • Handlerdocument.onscroll or addEventListener("scroll", ...).
  • Position — read window.scrollY / scrollX (or scrollingElement.scrollTop).
  • Performance — throttle expensive work; MDN prefers measuring timeouts with setTimeout.
  • Status — Baseline Widely available since July 2015 (MDN).

📝 Syntax

Use the event name with addEventListener, or set the handler property:

JavaScript
addEventListener("scroll", (event) => { });

onscroll = (event) => { };

Event type

A generic Event.

Minimal listener

JavaScript
document.addEventListener("scroll", () => {
  console.log("scrollY:", window.scrollY);
});

⚡ Why Throttle Scroll Handlers?

MDN: scroll can fire at a high rate. Do not run heavy DOM modifications on every event. If fast scrolling feels janky, throttle.

  • Do measure your own interval with setTimeout (MDN example uses ~20ms).
  • Avoid thinking requestAnimationFrame alone throttles scroll—MDN notes animation frame callbacks fire at a similar rate.
  • Consider IntersectionObserver for “did this section enter the viewport?” instead of scroll math.

⚡ Quick Reference

GoalCode / note
Listendocument.addEventListener("scroll", fn)
Handler propertydocument.onscroll = fn
Vertical positionwindow.scrollY
Scrolling rootdocument.scrollingElement
ThrottlesetTimeout gate (MDN)—not rAF alone
MDN statusBaseline Widely available (Jul 2015)

🔍 At a Glance

Four facts to remember about Document scroll.

Event type
Event

Plain Event

Means
View scrolled

Page moved

Read
scrollY

Vertical offset

Perf
Throttle

Keep handlers light

Examples Gallery

Examples follow MDN Document: scroll event. Try-it labs include tall content so you can scroll and see updates.

📚 Getting Started

Listen on Document and use the handler property.

Example 1 — Basic Document Listener

Show window.scrollY whenever the document view scrolls.

JavaScript
const out = document.getElementById("out");

document.addEventListener("scroll", () => {
  out.textContent = "scrollY: " + Math.round(window.scrollY);
});
Try It Yourself

How It Works

Each scroll movement updates the label. This is fine for tiny demos; production UIs that touch many DOM nodes should throttle (next examples).

Example 2 — document.onscroll

Use the handler property to mirror the same idea.

JavaScript
const out = document.getElementById("out");

document.onscroll = () => {
  out.textContent =
    "onscroll → Y=" + Math.round(window.scrollY) +
    " X=" + Math.round(window.scrollX);
};
Try It Yourself

How It Works

Prefer addEventListener when more than one module needs scroll. The property form is handy for short tutorials.

📈 Throttle, Progress & UI

MDN throttling pattern plus common page-scroll UI patterns.

Example 3 — Scroll Throttling (MDN)

Store the latest position, then run work at most every 20ms via setTimeout.

JavaScript
let lastKnownScrollPosition = 0;
let ticking = false;
const out = document.getElementById("out");

function doSomething(scrollPos) {
  out.textContent = "Throttled work @ " + Math.round(scrollPos);
}

document.addEventListener("scroll", () => {
  lastKnownScrollPosition = window.scrollY;

  if (!ticking) {
    setTimeout(() => {
      doSomething(lastKnownScrollPosition);
      ticking = false;
    }, 20);

    ticking = true;
  }
});
Try It Yourself

How It Works

MDN’s pattern: update the stored position on every event, but only schedule expensive work if a timer is not already pending. That is real throttling with a measured timeout.

Example 4 — Reading Progress Bar

Map scroll position to a 0–100% progress width (common blog UI).

JavaScript
const bar = document.getElementById("bar");
const label = document.getElementById("label");

function updateProgress() {
  const doc = document.documentElement;
  const max = doc.scrollHeight - doc.clientHeight;
  const pct = max > 0 ? Math.min(100, (window.scrollY / max) * 100) : 0;
  bar.style.width = pct + "%";
  label.textContent = Math.round(pct) + "% read";
}

document.addEventListener("scroll", updateProgress, { passive: true });
updateProgress();
Try It Yourself

How It Works

{ passive: true } tells the browser you will not call preventDefault(), which can help scrolling stay smooth. For heavier paint work, combine this with the throttle pattern from Example 3.

Example 5 — Show “Back to Top” After Scroll

Reveal a button once the user has scrolled past a threshold.

JavaScript
const btn = document.getElementById("top");

document.addEventListener("scroll", () => {
  btn.hidden = window.scrollY < 200;
}, { passive: true });

btn.addEventListener("click", () => {
  window.scrollTo({ top: 0, behavior: "smooth" });
});
Try It Yourself

How It Works

A simple threshold check is cheap enough to run on most scroll events. If you add animations or layout thrashing, throttle first.

🚀 Common Use Cases

  • Sticky / shrinking headers that react to scroll position.
  • Reading progress indicators on long articles.
  • “Back to top” and floating action buttons.
  • Lazy UI that loads more content near the bottom (with care / IntersectionObserver).
  • Teaching high-frequency events and throttling.

🔧 How It Works

1

User scrolls the page

Wheel, touch, keyboard, scrollbar, or scrollTo moves the document view.

Input
2

Document fires scroll

Your listener runs—often many times while motion continues.

Notify
3

Read position

Use window.scrollY or scrollingElement.scrollTop.

Measure
4

Update UI carefully

Throttle heavy work; consider scrollend or IntersectionObserver.

📝 Notes

  • Baseline Widely available (since July 2015)—no Deprecated / Experimental / Non-standard banner.
  • Keep handlers light; throttle with setTimeout per MDN guidance.
  • Element overflow scrolling uses Element scroll, not Document scroll.
  • For “scrolling finished,” see Document scrollend.
  • Related learning: scrollingElement, scrollTop, JavaScript hub.

Universal Browser Support

Document scroll is marked Baseline Widely available on MDN (since July 2015). Logos use the shared browser-image-sprite.png sprite from this project. It is a standard Document event used across modern browsers.

Baseline · Widely available

Document scroll

Fires when the document view has been scrolled. Pair with window.scrollY and throttle expensive work.

Universal Widely available
Google Chrome Full support · Desktop & Mobile
Full support
Mozilla Firefox Full support · Desktop & Mobile
Full support
Apple Safari Full support · macOS & iOS
Full support
Microsoft Edge Full support · Chromium & Legacy
Full support
Opera Full support · Modern versions
Full support
Internet Explorer Long-supported (prefer modern browsers)
Legacy
scroll Excellent

Bottom line: Listen on document for scroll, read window.scrollY, throttle heavy UI updates with setTimeout, and use IntersectionObserver for threshold-based visibility.

Conclusion

Document scroll is the standard page-scroll signal. Read window.scrollY, keep callbacks cheap, and throttle the MDN way when you must touch the DOM. For finished motion use scrollend; for section visibility prefer IntersectionObserver.

Continue with scrollend, scrollingElement, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Use Document scroll for page-level scrolling
  • Read window.scrollY / scrollingElement
  • Throttle heavy work with setTimeout (MDN)
  • Consider { passive: true } when you never call preventDefault()
  • Prefer IntersectionObserver for enter-viewport logic

❌ Don’t

  • Run expensive DOM work on every scroll tick
  • Assume rAF alone throttles scroll (MDN)
  • Listen on Document for a nested overflow box
  • Confuse continuous scroll with finished scrollend
  • Treat this API as Experimental—it is Baseline

Key Takeaways

Knowledge Unlocked

Five things to remember about Document scroll

Page scrolled — read scrollY and keep handlers light.

5
Core concepts
🔍 02

Read Y

window.scrollY

API
⏱️ 03

Throttle

setTimeout gate

Perf
👁 04

Alt

IntersectionObserver

MDN
05

Baseline

widely available

Compat

❓ Frequently Asked Questions

It fires when the document view has been scrolled. For element overflow scrolling, use the Element scroll event instead. To detect when scrolling has finished, see Document scrollend.
No. MDN marks Document scroll as Baseline Widely available (since July 2015). It is not Deprecated, Experimental, or Non-standard.
Scroll fires at a high rate. Avoid heavy DOM work on every event. MDN recommends throttling with setTimeout (measuring your own timeout). Using requestAnimationFrame alone to throttle scroll is not useful because it runs at a similar rate.
Commonly use window.scrollY (and window.scrollX). You can also use document.scrollingElement.scrollTop for the scrolling root element.
Yes. You can use document.onscroll or document.addEventListener("scroll", ...).
MDN suggests IntersectionObserver for threshold-based listening (for example, when a section enters the viewport) instead of computing visibility on every scroll event.
Did you know?

MDN explicitly calls out a common mistake: wrapping scroll work in requestAnimationFrame and calling that “throttling.” Because animation frames and scroll events often fire at similar rates, you should measure your own timeout (for example with setTimeout) when you need fewer updates.

Next: Document scrollend

Learn the Document event that fires when document scrolling has finished.

scrollend →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful