Now.js Framework Documentation
ScrollManager
ScrollManager
Overview
ScrollManager is a comprehensive and modern scrolling management system designed to provide smooth scrolling experiences with support for animations, waypoints, parallax effects, infinite scroll, and other advanced features.
Key Features:
- Customizable smooth scrolling
- Waypoints and Intersection Observer
- Scroll restoration (remembers position on back navigation)
- Mobile support (touch events)
- Accessibility features (ARIA, keyboard navigation)
- Performance optimization (throttle, debounce, RAF)
- Parallax effects
- Infinite scroll
- Scroll progress indicator
- Section highlighting
- Multiple animation easing functions
Installation and Import
ScrollManager is loaded with the Now.js Framework and is ready to use immediately via the window object:
// No import needed - ready to use immediately
console.log(window.ScrollManager); // ScrollManager objectConfiguration
Main Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
Boolean | false |
Enable/disable ScrollManager |
core.offset |
Number | 0 |
Offset from top (px) |
core.duration |
Number | 500 |
Animation duration (ms) |
core.easing |
String | "easeInOutCubic" |
Easing function |
Advanced Configuration
Animation Options
animation: {
enabled: true,
types: {
linear: t => t,
easeInOutCubic: t => ...,
easeOutQuart: t => ...,
easeInQuad: t => t * t
}
}Performance Options
performance: {
throttle: 16, // ms for throttle scroll events
debounce: 100, // ms for debounce
passive: true, // use passive event listeners
observer: true, // use IntersectionObserver
requestAnimationFrame: {
enabled: true,
maxFPS: 60,
skipThreshold: 16
},
batchSize: 5,
maxQueue: 100
}Restoration Options
restoration: {
enabled: true,
key: 'scroll_positions',
ttl: 24 * 60 * 60 * 1000 // 24 hours
}Mobile Options
mobile: {
enabled: true,
touchAction: 'pan-y',
momentumScroll: true,
pullToRefresh: false,
touchThreshold: 5
}Accessibility Options
accessibility: {
enabled: true,
announceChanges: true,
smoothFocus: true,
ariaLabels: true,
focusableSelectors: '...'
}Waypoints Options
waypoints: {
offset: 0,
threshold: 0.5,
once: false,
delay: 100
}Scroll Features
scroll: {
infinite: {
enabled: false,
threshold: 100,
loadMore: null
},
parallax: {
enabled: false,
speed: 0.5
},
progress: {
enabled: false,
color: 'var(--color-primary)',
height: '3px',
zIndex: 1000
},
snap: {
enabled: false,
type: 'y',
stop: true,
align: 'start'
},
section: {
highlight: true,
threshold: 0.5,
activeClass: 'active'
},
nav: {
updateHash: true,
highlightClass: 'active',
smoothScroll: true
}
}Smooth Scroll Options
smoothScroll: {
enabled: false,
autoScroll: false,
selector: 'a[href^="#"]',
excludeSelector: '.no-smooth',
hashChangeEnabled: true
}Initialization
// Auto-initialize (requires enabled: true)
ScrollManager.init({
enabled: true
});
// Initialize with custom config
ScrollManager.init({
enabled: true,
core: {
offset: 80, // for fixed header
duration: 600
},
smoothScroll: {
enabled: true,
selector: 'a[href^="#"]'
},
waypoints: {
threshold: 0.7,
once: false
},
performance: {
throttle: 16,
debounce: 150
}
});Methods
init(options)
Initialize ScrollManager
Parameters:
options(Object, optional): Configuration options
Returns: Promise<ScrollManager>
Example:
await ScrollManager.init({
enabled: true,
core: { offset: 100, duration: 600 },
smoothScroll: { enabled: true }
});scrollTo(target, options)
Scroll to specified element or selector
Parameters:
target(String|HTMLElement): CSS selector or elementoptions(Object, optional): Scroll optionsoffset(Number): Offset from topduration(Number): Animation durationeasing(String): Easing function namefocus(Boolean): Focus element after scroll (default: true)
Returns: Promise<void>
Example:
// Scroll to element
await ScrollManager.scrollTo('#section-about');
// Scroll with options
await ScrollManager.scrollTo('#contact', {
offset: 100,
duration: 1000,
easing: 'easeOutQuart'
});
// Scroll using element directly
const element = document.querySelector('.target');
await ScrollManager.scrollTo(element, {
offset: 80
});scrollToTop(options)
Scroll to top of page
Parameters:
options(Object, optional): Scroll options
Returns: Promise<void>
Example:
await ScrollManager.scrollToTop();
// With animation
await ScrollManager.scrollToTop({
duration: 800,
easing: 'easeInOutCubic'
});scrollToBottom(options)
Scroll to bottom of page
Parameters:
options(Object, optional): Scroll options
Returns: Promise<void>
Example:
await ScrollManager.scrollToBottom();
await ScrollManager.scrollToBottom({
duration: 600
});scrollToContent(options)
Scroll to main content area
Parameters:
options(Object, optional): Scroll options
Returns: Promise<void>
Example:
// Scroll to #main
await ScrollManager.scrollToContent();addWaypoint(id, element, options)
Add waypoint to detect when element comes into view
Parameters:
id(String): Unique waypoint IDelement(HTMLElement): Element to trackoptions(Object, optional): Waypoint optionsoffset(Number): Offset valuethreshold(Number): Visibility percentage (0-1)once(Boolean): Trigger only oncecallback(Function): Function to call on trigger
Returns: void
Example:
const element = document.querySelector('.animate-on-scroll');
ScrollManager.addWaypoint('my-waypoint', element, {
threshold: 0.5,
once: true,
callback: (entry) => {
console.log('Element is visible!');
element.classList.add('animated');
}
});removeWaypoint(id)
Remove existing waypoint
Parameters:
id(String): Waypoint ID to remove
Returns: void
Example:
ScrollManager.removeWaypoint('my-waypoint');cancelScroll()
Cancel currently active scroll
Returns: void
Example:
ScrollManager.cancelScroll();getScrollPosition()
Get current scroll position
Returns: Object - {x, y, percentX, percentY}
Example:
const position = ScrollManager.getScrollPosition();
console.log(position);
// { x: 0, y: 500, percentX: 0, percentY: 25 }on(event, handler)
Register event listener
Parameters:
event(String): Event namehandler(Function): Handler function
Returns: void
Example:
ScrollManager.on('scroll:complete', (data) => {
console.log('Scrolled to:', data.element);
});
ScrollManager.on('waypoint:trigger', (data) => {
console.log('Waypoint triggered:', data.id);
});off(event, handler)
Remove event listener
Parameters:
event(String): Event namehandler(Function): Handler function
Returns: void
Example:
const handler = (data) => console.log(data);
ScrollManager.on('scroll:complete', handler);
// use...
ScrollManager.off('scroll:complete', handler);emit(eventName, data)
Emit custom event
Parameters:
eventName(String): Event namedata(Any): Data to send
Returns: void
Example:
ScrollManager.emit('custom:scroll', {
position: 100,
target: 'section-about'
});cleanup()
Clean up and stop all operations
Returns: void
Example:
ScrollManager.cleanup();Events
ScrollManager emits various events that can be listened to:
| Event | Description | Data |
|---|---|---|
scroll:initialized |
Initialization complete | - |
scroll:start |
Scroll starts | {element, options} |
scroll:complete |
Scroll complete | {element, position} |
scroll:cancel |
Scroll canceled | - |
scroll:progress |
Scrolling (throttled) | {x, y, percentX, percentY} |
scroll:end |
Scroll ended and stopped | {x, y, percentX, percentY} |
scroll:direction |
Scroll direction changed | {direction: 'up'\|'down'} |
scroll:animationComplete |
Animation complete | {startY, targetY, duration} |
scroll:reveal |
Element revealed | {element} |
waypoint:trigger |
Waypoint triggered | {id, entry} |
section:active |
New section became active | {id} |
touch:move |
Touch move (mobile) | {diffY, diffX, originalEvent} |
scroll:error |
Error occurred | {error} |
Event Usage Examples:
// Listen to scroll complete
ScrollManager.on('scroll:complete', (data) => {
console.log('Scrolled to:', data.element.id);
console.log('Position:', data.position);
});
// Listen to scroll direction
ScrollManager.on('scroll:direction', (data) => {
if (data.direction === 'down') {
header.classList.add('hidden');
} else {
header.classList.remove('hidden');
}
});
// Listen to waypoint
ScrollManager.on('waypoint:trigger', (data) => {
console.log('Waypoint:', data.id);
});
// Listen to scroll progress
ScrollManager.on('scroll:progress', (position) => {
progressBar.style.width = position.percentY + '%';
});HTML Data Attributes
ScrollManager supports data attributes for behavior control:
Waypoints
<!-- Basic waypoint -->
<div data-scroll-waypoint="section-1">
Content
</div>
<!-- Waypoint with offset -->
<div data-scroll-waypoint="section-2"
data-scroll-offset="100">
Content
</div>
<!-- Waypoint with callback -->
<div data-scroll-waypoint="section-3"
data-scroll-callback="onSectionVisible">
Content
</div>Scroll Reveal
<!-- Element gets 'revealed' class when in view -->
<div data-scroll-reveal>
Animate me!
</div>Scroll Section
<!-- Sections that will be tracked and highlighted -->
<section id="about" data-scroll-section>
About Us
</section>
<section id="services" data-scroll-section>
Our Services
</section>Scroll Navigation
<!-- Navigation links -->
<nav data-scroll-nav>
<a href="#home">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>Parallax
<!-- Parallax element -->
<div data-parallax data-parallax-speed="0.5">
Background Layer
</div>Ignore Smooth Scroll
<!-- Don't use smooth scroll for this element -->
<a href="#skip" data-scroll-ignore>Skip smooth scroll</a>Usage Examples
1. Basic Smooth Scrolling
// Enable smooth scrolling
ScrollManager.init({
enabled: true,
smoothScroll: {
enabled: true,
selector: 'a[href^="#"]'
},
core: {
offset: 80, // for fixed header
duration: 600
}
});<nav>
<a href="#home">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
<section id="home">...</section>
<section id="about">...</section>
<section id="contact">...</section>2. Scroll-triggered Animations
await ScrollManager.init({
enabled: true,
waypoints: {
threshold: 0.3,
once: true
}
});
// Add waypoints
document.querySelectorAll('.animate-on-scroll').forEach((el, i) => {
ScrollManager.addWaypoint(`anim-${i}`, el, {
threshold: 0.3,
once: true,
callback: (entry) => {
el.classList.add('animated', 'fadeInUp');
}
});
});<div class="animate-on-scroll">
This will animate when scrolled into view
</div>
<div class="animate-on-scroll">
Another animated element
</div>.animate-on-scroll {
opacity: 0;
transform: translateY(50px);
transition: all 0.6s ease;
}
.animate-on-scroll.animated {
opacity: 1;
transform: translateY(0);
}3. Scroll to Top Button
ScrollManager.init({
enabled: true,
core: { duration: 800 }
});
const scrollTopBtn = document.querySelector('.scroll-top');
// Show button when scrolling down
ScrollManager.on('scroll:progress', (position) => {
if (position.y > 300) {
scrollTopBtn.classList.add('visible');
} else {
scrollTopBtn.classList.remove('visible');
}
});
// Click to go to top
scrollTopBtn.addEventListener('click', () => {
ScrollManager.scrollToTop({
duration: 800,
easing: 'easeOutQuart'
});
});<button class="scroll-top">↑</button>.scroll-top {
position: fixed;
bottom: 20px;
right: 20px;
opacity: 0;
visibility: hidden;
transition: all 0.3s;
}
.scroll-top.visible {
opacity: 1;
visibility: visible;
}4. Hide Header on Scroll Down
ScrollManager.init({
enabled: true
});
const header = document.querySelector('.header');
ScrollManager.on('scroll:direction', (data) => {
if (data.direction === 'down') {
header.classList.add('header-hidden');
} else {
header.classList.remove('header-hidden');
}
});.header {
position: fixed;
top: 0;
width: 100%;
transition: transform 0.3s;
}
.header-hidden {
transform: translateY(-100%);
}5. Section Highlighting in Navigation
ScrollManager.init({
enabled: true,
scroll: {
section: {
highlight: true,
threshold: 0.5,
activeClass: 'active'
},
nav: {
updateHash: true,
highlightClass: 'active'
}
}
});
// Navigation gets active class automatically
ScrollManager.on('section:active', (data) => {
// Update navigation
document.querySelectorAll('[data-scroll-nav] a').forEach(link => {
link.classList.remove('active');
});
const activeLink = document.querySelector(`[href="#${data.id}"]`);
if (activeLink) {
activeLink.classList.add('active');
}
});<nav data-scroll-nav>
<a href="#section1">Section 1</a>
<a href="#section2">Section 2</a>
<a href="#section3">Section 3</a>
</nav>
<section id="section1" data-scroll-section>...</section>
<section id="section2" data-scroll-section>...</section>
<section id="section3" data-scroll-section>...</section>6. Scroll Progress Bar
ScrollManager.init({
enabled: true,
scroll: {
progress: {
enabled: true,
color: '#4CAF50',
height: '4px',
zIndex: 9999
}
}
});
// Or create custom progress bar
const progressBar = document.querySelector('.progress-bar');
ScrollManager.on('scroll:progress', (position) => {
progressBar.style.width = position.percentY + '%';
});<div class="scroll-progress">
<div class="progress-bar"></div>
</div>.scroll-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: rgba(0,0,0,0.1);
z-index: 9999;
}
.progress-bar {
height: 100%;
background: #4CAF50;
width: 0%;
transition: width 0.1s;
}7. Parallax Effect
ScrollManager.init({
enabled: true,
scroll: {
parallax: {
enabled: true,
speed: 0.5
}
}
});
// Custom parallax
const parallaxElements = document.querySelectorAll('[data-parallax]');
ScrollManager.on('scroll:progress', (position) => {
parallaxElements.forEach(el => {
const speed = parseFloat(el.dataset.parallaxSpeed) || 0.5;
const yPos = -(position.y * speed);
el.style.transform = `translateY(${yPos}px)`;
});
});<div class="hero">
<div class="hero-bg" data-parallax data-parallax-speed="0.5">
Background
</div>
<div class="hero-content" data-parallax data-parallax-speed="0.2">
Content
</div>
</div>8. Infinite Scroll
ScrollManager.init({
enabled: true,
scroll: {
infinite: {
enabled: true,
threshold: 200, // Load when 200px from bottom
loadMore: async () => {
console.log('Loading more content...');
const newContent = await fetchMoreContent();
appendContent(newContent);
}
}
}
});
async function fetchMoreContent() {
const response = await fetch('/api/load-more');
return await response.json();
}
function appendContent(data) {
const container = document.querySelector('.content-container');
data.forEach(item => {
const div = document.createElement('div');
div.innerHTML = item.html;
container.appendChild(div);
});
}State Properties
| Property | Type | Description |
|---|---|---|
state.initialized |
Boolean | Initialization status |
state.isScrolling |
Boolean | Currently scrolling |
state.isLoading |
Boolean | Currently loading data |
state.activeAnimation |
Number|null | Current animation RAF ID |
state.positions |
Map | Stored scroll positions |
state.waypoints |
Map | All waypoints |
state.observers |
Map | Observers (Intersection, Mutation, Resize) |
state.events |
Map | Event handlers |
state.history |
Array | Scroll position history |
state.lastPosition |
Object|null | Last position |
state.scrollDirection |
String|null | Scroll direction ('up'|'down') |
state.activeSection |
String|null | Currently active section |
Example:
// Check status
if (ScrollManager.state.initialized) {
console.log('Ready');
}
if (ScrollManager.state.isScrolling) {
console.log('Currently scrolling');
}
// View history
console.log(ScrollManager.state.history);
// View all waypoints
ScrollManager.state.waypoints.forEach((waypoint, id) => {
console.log(id, waypoint);
});Easing Functions
ScrollManager has built-in easing functions:
| Function | Description | Best For |
|---|---|---|
linear |
Constant speed | Simple movement |
easeInOutCubic |
Slow-fast-slow | General scrolling (default) |
easeOutQuart |
Gradually slow down | Soft stop |
easeInQuad |
Gradually speed up | Slow start |
easeOutBack |
Overshoot and return | Special effects |
Example:
ScrollManager.scrollTo('#target', {
duration: 1000,
easing: 'easeOutQuart' // Use easing function
});Custom Easing:
ScrollManager.config.animation.types.myCustomEasing = (t) => {
return t * t * (3 - 2 * t); // smoothstep
};
ScrollManager.scrollTo('#target', {
easing: 'myCustomEasing'
});Integration
With RouterManager
// ScrollManager works automatically with RouterManager
RouterManager.init({
mode: 'history',
scrollToTop: true
});
ScrollManager.init({
enabled: true,
restoration: {
enabled: true // Remember position on back
}
});
// Auto scroll to top on route change
RouterManager.on('route:changed', async (data) => {
if (data.scrollToTop !== false) {
await ScrollManager.scrollToTop();
}
});With ResponseHandler
// API response can control scrolling
ResponseHandler.registerHandler('scrollTo', async (action) => {
await ScrollManager.scrollTo(action.target, action.options);
});
// API Response
{
"success": true,
"actions": [
{
"type": "scrollTo",
"target": "#success-message",
"options": {
"offset": 100,
"duration": 600
}
}
]
}With Animation Libraries
// Use with GSAP, AOS, Animate.css
ScrollManager.init({
enabled: true,
waypoints: { threshold: 0.3, once: true }
});
// AOS Integration
document.querySelectorAll('[data-aos]').forEach((el, i) => {
ScrollManager.addWaypoint(`aos-${i}`, el, {
threshold: 0.3,
once: true,
callback: () => {
AOS.refresh();
}
});
});Best Practices
1. Enable Performance Features
ScrollManager.init({
enabled: true,
performance: {
throttle: 16,
debounce: 100,
passive: true,
observer: true,
requestAnimationFrame: {
enabled: true
}
}
});2. Use Throttle and Debounce
// Throttle for scroll events
const handleScroll = ScrollManager.throttle(() => {
// Runs every 16ms
}, 16);
// Debounce for resize
const handleResize = ScrollManager.debounce(() => {
// Runs 150ms after resize stops
}, 150);3. Clean Up When Not Used
// In SPA when changing page
RouterManager.on('route:before-change', () => {
ScrollManager.cleanup();
});
// Or in component lifecycle
onBeforeUnmount(() => {
ScrollManager.cleanup();
});4. Use Waypoints Instead of Scroll Event Listeners
❌ Not Recommended:
window.addEventListener('scroll', () => {
const element = document.querySelector('.target');
const rect = element.getBoundingClientRect();
if (rect.top < window.innerHeight) {
element.classList.add('visible');
}
});✅ Recommended:
ScrollManager.addWaypoint('target', element, {
threshold: 0.5,
once: true,
callback: () => {
element.classList.add('visible');
}
});5. Set Offset for Fixed Header
ScrollManager.init({
enabled: true,
core: {
offset: 80 // header height
}
});header {
position: fixed;
height: 80px;
}6. Use Once for Animations
// Animation triggers only once
ScrollManager.addWaypoint('anim', element, {
once: true, // Won't trigger again
callback: () => {
element.classList.add('animated');
}
});7. Check Browser Support
if (!('IntersectionObserver' in window)) {
// Use fallback
console.warn('IntersectionObserver not supported');
ScrollManager.init({
enabled: true,
performance: {
observer: false
}
});
}Common Pitfalls
1. Forgetting to Enable
// ❌ Won't work
ScrollManager.init({
smoothScroll: { enabled: true }
});
// ✅ Must enable: true
ScrollManager.init({
enabled: true,
smoothScroll: { enabled: true }
});2. Not Awaiting Async Methods
// ❌ May have issues
ScrollManager.scrollTo('#target');
doSomethingElse(); // Runs immediately
// ✅ Wait for completion
await ScrollManager.scrollTo('#target');
doSomethingElse(); // Runs after scroll3. Target Doesn't Exist
// ❌ May error
ScrollManager.scrollTo('#non-existent');
// ✅ Check first
const target = document.querySelector('#my-target');
if (target) {
await ScrollManager.scrollTo(target);
}4. Duplicate Waypoint IDs
// ❌ Will throw error
ScrollManager.addWaypoint('my-id', element1);
ScrollManager.addWaypoint('my-id', element2); // Error!
// ✅ Use unique IDs
ScrollManager.addWaypoint('waypoint-1', element1);
ScrollManager.addWaypoint('waypoint-2', element2);5. Not Cleaning Up
// ❌ Memory leak in SPA
// No cleanup when changing page
// ✅ Clean up when necessary
RouterManager.on('route:before-change', () => {
ScrollManager.cleanup();
});Performance
1. Use RequestAnimationFrame
ScrollManager.init({
enabled: true,
performance: {
requestAnimationFrame: {
enabled: true,
maxFPS: 60
}
}
});2. Use Passive Event Listeners
ScrollManager.init({
enabled: true,
performance: {
passive: true // Improves scroll performance
}
});3. Use IntersectionObserver
// More performant than scroll event listeners
ScrollManager.init({
enabled: true,
performance: {
observer: true
}
});4. Limit Waypoint Count
// ❌ Too many
document.querySelectorAll('.item').forEach((el, i) => {
ScrollManager.addWaypoint(`item-${i}`, el); // 1000+ waypoints
});
// ✅ Reasonable amount
document.querySelectorAll('.section').forEach((el, i) => {
ScrollManager.addWaypoint(`section-${i}`, el); // 10-20 waypoints
});5. Throttle Scroll Events
ScrollManager.init({
enabled: true,
performance: {
throttle: 16, // ~60fps
debounce: 100
}
});Security
1. Validate Selectors
// ❌ May have issues
const userInput = getUserInput();
ScrollManager.scrollTo(userInput); // Dangerous!
// ✅ Validate first
function safeScrollTo(selector) {
const element = document.querySelector(selector);
if (element && element.matches('[data-scrollable]')) {
ScrollManager.scrollTo(element);
}
}2. Check Callback Functions
// ✅ Verify callback is function
ScrollManager.addWaypoint('id', element, {
callback: (entry) => {
if (typeof window.onWaypoint === 'function') {
window.onWaypoint(entry);
}
}
});3. Limit Scroll Queue
ScrollManager.init({
enabled: true,
performance: {
maxQueue: 100 // Limit queue size
}
});Browser Compatibility
| Browser | Version | Support |
|---|---|---|
| Chrome | 60+ | ✅ Full |
| Firefox | 55+ | ✅ Full |
| Safari | 12+ | ✅ Full |
| Edge | 79+ | ✅ Full |
| iOS Safari | 12+ | ✅ Full |
| Chrome Android | 80+ | ✅ Full |
| IE | ❌ | Not Supported |
Required Features:
- ES6 (async/await, Map, Set)
- requestAnimationFrame
- IntersectionObserver (optional, uses fallback if unavailable)
- ResizeObserver (optional)
- MutationObserver (optional)
Polyfills:
<!-- For older browsers -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"></script>API Reference
Methods Summary
| Method | Parameters | Returns | Description |
|---|---|---|---|
init(options) |
options?: Object |
Promise<ScrollManager> |
Initialize |
scrollTo(target, options) |
target: String\|Element, options?: Object |
Promise<void> |
Scroll to target |
scrollToTop(options) |
options?: Object |
Promise<void> |
Scroll to top |
scrollToBottom(options) |
options?: Object |
Promise<void> |
Scroll to bottom |
scrollToContent(options) |
options?: Object |
Promise<void> |
Scroll to content area |
addWaypoint(id, element, options) |
id: String, element: Element, options?: Object |
void |
Add waypoint |
removeWaypoint(id) |
id: String |
void |
Remove waypoint |
cancelScroll() |
- | void |
Cancel scroll |
getScrollPosition() |
- | Object |
Get current position |
on(event, handler) |
event: String, handler: Function |
void |
Register event |
off(event, handler) |
event: String, handler: Function |
void |
Remove event |
emit(eventName, data) |
eventName: String, data?: Any |
void |
Emit event |
cleanup() |
- | void |
Clean up |
throttle(func, limit) |
func: Function, limit: Number |
Function |
Create throttled function |
debounce(func, wait) |
func: Function, wait: Number |
Function |
Create debounced function |
Live Examples
See ScrollManager in action with our comprehensive one-page scrolling example:
This example demonstrates:
- ✨ Smooth scrolling navigation
- 🎨 Parallax effects with multiple layers
- 👁️ Waypoint animations
- 📊 Scroll progress indicator
- 🔗 Section highlighting and hash updates
- 📱 Mobile-optimized touch interactions
- ⌨️ Keyboard navigation support
- 🎯 Interactive demo with real-time tracking
Visit the example to see all ScrollManager features working together in a beautiful one-page layout.
Summary
ScrollManager provides:
- Smooth scrolling - Smooth page scrolling with animations
- Waypoints - Detect when elements come into view
- Performance - Uses RAF, throttle, debounce, IntersectionObserver
- Accessibility - Supports keyboard, screen readers, ARIA
- Mobile-friendly - Supports touch events
- Flexible - Highly customizable with many events and callbacks
- Integration - Works with RouterManager, ResponseHandler
- Features - Parallax, infinite scroll, progress bar, section highlighting
Related Documentation
- One-Page Example - Complete scrolling demonstration
- RouterManager - Navigation and routing
- ComponentManager - Component lifecycle
- Now.js Documentation - Full framework documentation