Getting Started with NewScroller: Installation, API, and Best PracticesNewScroller is a lightweight, modern scrolling library designed to improve user experience by providing smooth, customizable scroll behavior across desktop and mobile browsers. It handles inertia, snap points, virtualized content, and exposes a small, expressive API so developers can tailor scrolling to their app’s needs without sacrificing performance.
Why use NewScroller?
- Smooth, consistent scrolling across browsers and devices
- Small footprint — minimal bundle size and few dependencies
- Customizable behaviors: easing, friction, momentum, and snap points
- Virtualization support for large lists to reduce DOM cost
- Accessibility-first — configurable keyboard focus handling and reduced-motion support
Installation
NewScroller is available via npm and CDN.
-
npm (recommended for most projects)
npm install newscroller
-
Yarn
yarn add newscroller
-
CDN (for quick prototyping)
<script src="https://cdn.example.com/newscroller/latest/newscroller.min.js"></script>
After installation, import NewScroller into your JavaScript:
// ESM import NewScroller from 'newscroller'; // CommonJS const NewScroller = require('newscroller');
For frameworks, NewScroller can be used directly or wrapped in a framework-specific component (React/Vue/Svelte). See the examples section for framework usage.
Core Concepts
- Container: the element that will host the custom scroll behavior (usually a div).
- Content: the inner element that is scrolled (children of the container).
- Scroll position: the offset (x, y) that NewScroller manages.
- Momentum/inertia: how NewScroller continues movement after a user stops dragging.
- Snap points: discrete positions (e.g., slides or cards) NewScroller can snap to.
- Virtualization: rendering only visible items in large lists.
Basic Usage
HTML structure:
<div id="scroller" class="scroller"> <div class="scroller-content"> <!-- long list of items --> </div> </div>
Initialize:
const scroller = new NewScroller(document.getElementById('scroller'), { direction: 'vertical', // 'vertical' | 'horizontal' | 'both' damping: 0.92, // momentum friction (0..1) bounce: true, // allow overscroll bounce scrollbars: true, // show custom scrollbars interactive: true // enable touch/mouse dragging });
API methods (common):
- scroller.scrollTo(x, y, options) — animate to position. Options: { duration, easing }.
- scroller.scrollBy(dx, dy, options) — relative scroll.
- scroller.getPosition() — returns { x, y }.
- scroller.on(event, handler) — listen to events (see Events section).
- scroller.destroy() — remove listeners and restore native behavior.
Configuration Options
Key options with recommended defaults:
- direction: ‘vertical’ — sets scrolling axis.
- damping: 0.92 — lower values = quicker stop; keep between 0.85–0.98.
- bounce: true — toggle overscroll bounce.
- snap: null | { points: […], threshold: 30, easing: ‘cubic-bezier(…)’ } — enables snap points.
- virtualize: false | { itemHeight, buffer } — turns on basic virtualization for lists.
- scrollbar: { visible: true, autoHide: true } — custom scrollbar behavior.
- keyboard: true — enable arrow/page keys navigation.
- reducedMotion: ‘auto’ — honors user prefers-reduced-motion setting.
Example with snap:
const scroller = new NewScroller(elem, { direction: 'horizontal', snap: { points: (container) => { // return array of x offsets for each slide return Array.from(container.querySelectorAll('.slide')).map((el) => el.offsetLeft); }, threshold: 40, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' } });
Events
NewScroller emits events for integration:
- ‘scroll’ — fires frequently during scroll with payload { x, y, velocity }
- ‘scrollStart’ — when user-initiated or programmatic scroll begins
- ‘scrollEnd’ — when motion stops
- ‘snap’ — when snap completes with { index, position }
- ‘reachStart’ / ‘reachEnd’ — when scroll reaches container bounds
- ‘virtualChange’ — when virtualization adds/removes items
Usage:
scroller.on('scroll', ({ x, y }) => { // update UI or lazy-load images });
Remove listener:
scroller.off('scroll', handler);
Virtualization (Large Lists)
Virtualization reduces DOM nodes by rendering only visible items.
Initialize virtualization:
const scroller = new NewScroller(listContainer, { direction: 'vertical', virtualize: { itemHeight: 80, buffer: 3 } });
Implement renderer:
scroller.on('virtualChange', ({ startIndex, endIndex }) => { renderItems(startIndex, endIndex); });
Tips:
- Use fixed item heights for best performance. Variable heights are supported but costlier.
- Keep item renderer idempotent and fast.
- Combine virtualization with lazy image loading.
Accessibility
- NewScroller honors prefers-reduced-motion by disabling animations when requested.
- Keyboard support: arrow keys, PageUp/PageDown, Home/End if keyboard option enabled.
- Screen readers: ensure content order in DOM remains logical; use aria-live or role attributes for dynamic content updates when necessary.
- Focus management: when focusing elements inside the scroller, call scroller.scrollIntoView(element, { animate: false }) to avoid disorienting animations.
Example:
scroller.scrollIntoView(document.querySelector('.focused-item'), { animate: false });
Performance Tips
- Avoid heavy DOM operations during ‘scroll’ events; debounce or use requestAnimationFrame.
- Prefer transform: translate3d for GPU-accelerated motion.
- Keep event handlers minimal; use scroller.on(‘scroll’, rAFThrottledHandler).
- Use virtualization for lists > 100 items.
- Batch DOM writes and reads to prevent layout thrashing.
Example requestAnimationFrame throttle:
let rafId = null; scroller.on('scroll', (pos) => { if (rafId) return; rafId = requestAnimationFrame(() => { updateProgressBar(pos.y); rafId = null; }); });
Common Patterns & Recipes
- Infinite scroll: listen to ‘reachEnd’ to load more data, then update content and call scroller.refresh().
- Pull-to-refresh: detect overscroll at start, show spinner, and trigger refresh on release.
- Carousel with snap: use snap.points derived from slide offsets and listen for ‘snap’ to update indicators.
- Lazy images: on ‘scroll’, check visible range and load images; better: use IntersectionObserver with virtualization.
Refreshing layout after DOM changes:
// After appending items scroller.refresh(); // recalculates sizes, snap points, virtualization ranges
Troubleshooting
- Scrolling feels jittery on mobile: ensure touch-action CSS is set correctly (touch-action: pan-y or pan-x), and disable passive listeners when necessary for gestures.
- Native scrollbars still visible: ensure container has overflow: hidden and NewScroller is initialized on the correct element.
- Snap not aligning: recalculate snap.points after images/fonts load or call scroller.refresh().
API Reference (Concise)
Methods:
- new NewScroller(container, options)
- scrollTo(x, y, { duration = 300, easing = ‘ease’ })
- scrollBy(dx, dy, opts)
- getPosition() -> { x, y }
- scrollIntoView(element, { align = ‘center’, animate = true })
- refresh()
- on(event, handler)
- off(event, handler)
- destroy()
Events: ‘scroll’, ‘scrollStart’, ‘scrollEnd’, ‘snap’, ‘reachStart’, ‘reachEnd’, ‘virtualChange’
Options: direction, damping, bounce, snap, virtualize, scrollbar, keyboard, reducedMotion
Example: React Integration
Minimal React hook:
import { useEffect, useRef } from 'react'; import NewScroller from 'newscroller'; export default function Scroller({ children }) { const ref = useRef(null); const scrollerRef = useRef(null); useEffect(() => { scrollerRef.current = new NewScroller(ref.current, { direction: 'vertical' }); return () => scrollerRef.current.destroy(); }, []); return ( <div ref={ref} className="scroller"> <div className="scroller-content">{children}</div> </div> ); }
Best Practices Summary
- Prefer minimal defaults; only enable features you need (snap, virtualization) to keep complexity low.
- Respect user preferences for reduced motion.
- Use virtualization for large lists and batch DOM updates.
- Keep event handlers lightweight and use rAF for UI updates.
- Test on real devices—mobile/browser differences matter for touch and performance.
NewScroller aims to be a flexible foundation for modern scroll-driven interfaces. With a small API surface, good defaults, and explicit controls for performance and accessibility, it can handle everything from simple content panes to complex carousels and virtualized feeds.
Leave a Reply