Zenscroll

A 1.4KB dependency-free vanilla JavaScript library for smooth animated scrolling to elements, positions, or centered targets.

Library
npm
v4.0.2
513stars
Unlicense

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance20
Community52
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
54/100Fair
Architecture78
Code Quality35
Innovation68
Learning Curve35

Zenscroll is a tiny vanilla JavaScript library that adds smooth, animated vertical scrolling to any page or scrollable element, with zero dependencies and a footprint of just 1.4 kilobytes minified and gzipped. Once included, it automatically intercepts clicks on same-page anchor links and animates the scroll instead of jumping, while also supporting programmatic scrolling to a specific element, a Y position, or the center of the viewport.

Beyond basic scroll-to behavior, Zenscroll handles edge cases that many larger scrolling libraries skip: it respects an edge offset for fixed navigation bars, restores scroll position on browser back/forward navigation via the History API, falls back gracefully to native CSS scroll-behavior: smooth when available, and can create independent scrollers scoped to any scrollable container (like a DIV) via createScroller(). Its UMD wrapper makes it usable via AMD, CommonJS/npm, or a plain script tag, and it maintains support down to very old browsers (IE6+, iOS Safari 3+) as a deliberate design goal.

What You Get

  • A default document-level scroller (zenscroll) usable immediately after the script loads, with to(), toY(), intoView(), and center() methods
  • Automatic smooth-scrolling on same-page anchor links, wired up on script load with no configuration required
  • createScroller() to instantiate an independent scroller scoped to any scrollable container element (a DIV, panel, etc.)
  • Configurable edge offset and scroll duration, either globally via setup() or per-scroller at creation time
  • Optional onDone completion callbacks on every scroll method, plus moving() and stop() for controlling in-flight scrolls
  • Automatic fallback to the browser’s native scroll-behavior: smooth when it’s enabled, while still animating manually in browsers that lack it

Common Use Cases

  • Smoothing in-page navigation for anchor-link menus (table of contents, one-page marketing sites) with no extra JavaScript
  • Scrolling a newly revealed or validated form field into view after a dynamic UI change
  • Building a custom in-page image gallery or carousel that scrolls a DIV’s contents via createScroller()
  • Offsetting scroll targets to account for a fixed header or footer bar so anchored content isn’t hidden behind it
  • Restoring the user’s scroll position correctly when they use the browser back/forward buttons on a long page

Under The Hood

Architecture Zenscroll is a single UMD-wrapped IIFE built around one core abstraction: makeScroller(container, defaultDuration, edgeOffset), a factory function that closes over a small container interface (body, toY, getY, getHeight, getTopOf) and returns a scroller object exposing to, toY, intoView, center, stop, moving, setup, getY, and getTopOf. The library instantiates one scroller for the document itself (backed by window.scrollTo/window.scrollY) and lets consumers create additional scrollers scoped to any DIV via createScroller(), which supplies the same container interface backed by element.scrollTop. All state (the active scroll’s timeout handle) lives in closured variables per scroller instance rather than in any shared store. A single global click listener, installed conditionally at load time (skipped if noZensmooth is set or native scroll-behavior: smooth is already active), drives the automatic anchor-link smoothing and integrates with history.scrollRestoration for back/forward navigation. Because every scroller — the document root and every createScroller() instance — depends on the same five-method container contract, any change to that shape would break both code paths simultaneously.

Tech Stack The library is written in plain ES5-era vanilla JavaScript (var, function expressions) with zero runtime dependencies — package.json declares neither dependencies nor devDependencies. There is no bundler, transpiler, or build script; the repo ships both hand-written source (zenscroll.js) and pre-minified (zenscroll-min.js) files directly, alongside an older zenscroll5.js/zenscroll5-min.js variant, with no npm scripts wiring the two together. The UMD wrapper at the top of the file supports AMD (define), CommonJS (module.exports), and plain global (window.zenscroll) consumption, and the package is published to npm as well as usable from a raw <script> tag. The only CI configured is a GitHub CodeQL security-scanning workflow, which runs against a dist branch rather than main.

Code Quality No automated test suite or test files exist anywhere in the repository, and there is no linter or formatter configuration beyond a bare .editorconfig for indentation style. Error handling is minimal by design: a single try/catch guards a known Chrome file:// protocol exception around history.replaceState, while the rest of the code relies on straightforward feature detection ("getComputedStyle" in window, "history" in window) rather than throwing or catching. Naming is consistent and readable throughout (scrollToY, getTopWithEdgeOffset, isNativeSmoothScrollEnabledOn), and each public method carries a JSDoc-style comment describing its parameters, but there is no type system — no TypeScript, no shipped type declarations, and no JSDoc @param type annotations.

API Design The public surface is small and consistent: to, toY, intoView, and center all share the same (target, duration, onDone) shape (center inserts an extra offset parameter before the callback), which makes the four methods easy to learn together. Zero-configuration is the default — including the script tag alone enables automatic anchor-link smoothing — and opting out requires only setting window.noZensmooth before the script loads. The callback-based onDone pattern (no Promises) is dated by modern standards but deliberate, since it preserves compatibility with the very old browsers the README explicitly targets. Documentation is unusually thorough for a project this small, with a numbered, example-driven walkthrough in the README covering every method and configuration combination.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search