Now.js Framework Documentation

Now.js Framework Documentation

ScrollManager

EN 04 Sep 2026 01:40

ScrollManager

Overview

ScrollManager is the scroll behavior management system in Now.js Framework. It supports smooth scrolling, waypoints, scroll tracking, and infinite scroll.

When to use:

  • Need smooth scroll to element
  • Need scroll waypoints/triggers
  • Need infinite scroll
  • Need scroll restoration
  • Need scroll navigation

Why use it:

  • ✅ Smooth scrolling with easing
  • ✅ Waypoints and triggers
  • ✅ Infinite scroll support
  • ✅ Scroll position persistence
  • ✅ Mobile touch support
  • ✅ Accessibility features

Basic Usage

Initialization

await ScrollManager.init({
  enabled: true,
  smoothScroll: {
    enabled: true,
    selector: 'a[href^="#"]'
  }
});

Smooth Scroll to Element

// Scroll to element
await ScrollManager.scrollTo('#section-2');

// With options
await ScrollManager.scrollTo('#contact', {
  offset: -100,    // Offset from top
  duration: 800,   // Animation duration
  easing: 'easeInOutCubic'
});

Scroll to Position

// Scroll to top
await ScrollManager.scrollToTop();

// Scroll to bottom
await ScrollManager.scrollToBottom();

// Scroll to specific position
await ScrollManager.scrollTo(500);  // 500px from top

Configuration

await ScrollManager.init({
  enabled: true,

  core: {
    offset: 0,              // Global offset
    duration: 500,          // Default animation duration
    easing: 'easeInOutCubic'
  },

  smoothScroll: {
    enabled: true,
    selector: 'a[href^="#"]',
    excludeSelector: '.no-smooth',
    hashChangeEnabled: true
  },

  waypoints: {
    enabled: true,
    threshold: 0.5,         // Visibility threshold
    offset: '0px'
  },

  infiniteScroll: {
    enabled: false,
    threshold: 0.9
  },

  persistence: {
    enabled: true,
    key: 'scroll_positions'
  },

  mobile: {
    enabled: true,
    touchAction: 'pan-y',
    momentumScroll: true
  }
});

API Reference

ScrollManager.scrollTo(target, options)

Scroll to target

Parameter Type Description
target string/number/HTMLElement Selector, position, or element
options.offset number Offset from target (px)
options.duration number Animation duration (ms)
options.easing string Easing function
options.onComplete function Callback on complete

Returns: Promise<void>

await ScrollManager.scrollTo('#features', {
  offset: -80,
  duration: 600
});

ScrollManager.scrollToTop(options)

Scroll to top

await ScrollManager.scrollToTop({ duration: 500 });

ScrollManager.scrollToBottom(options)

Scroll to bottom

await ScrollManager.scrollToBottom();

ScrollManager.scrollToContent(options)

Scroll to main content

await ScrollManager.scrollToContent();

ScrollManager.getScrollPosition()

Get current position

Returns: Object - { x, y, direction }

const pos = ScrollManager.getScrollPosition();
console.log(`Scroll Y: ${pos.y}`);

ScrollManager.addWaypoint(id, element, options)

Add waypoint

Parameter Type Description
id string Waypoint ID
element HTMLElement Element to watch
options.onEnter function Callback when entering viewport
options.onLeave function Callback when leaving viewport
options.threshold number Visibility threshold (0-1)
ScrollManager.addWaypoint('section-1', document.getElementById('section-1'), {
  onEnter: () => console.log('Section 1 visible'),
  onLeave: () => console.log('Section 1 hidden'),
  threshold: 0.5
});

ScrollManager.removeWaypoint(id)

Remove waypoint

ScrollManager.removeWaypoint('section-1');

ScrollManager.cancelScroll()

Cancel current animation

ScrollManager.cancelScroll();

Easing Functions

Easing Description
linear Constant speed
easeInOutCubic Smooth start and end
easeOutQuart Fast start, slow end
easeInQuad Slow start, fast end
easeOutBack Overshoot and settle

Data Attributes

Attribute Description
data-scroll-waypoint Turns the element into a waypoint, using the value as its id
data-scroll-offset Offset for this waypoint, in pixels
data-scroll-callback Name of a window function called when the waypoint triggers
data-parallax-speed Parallax speed for this element, overriding the config

Events

Event When Triggered Detail
scroll:initialized init() completed none
scroll:start Scroll animation starts {element, options}
scroll:progress During scroll {position, progress, total}
scroll:end Scrolling settled (debounced) position (sent directly, not wrapped)
scroll:complete scrollTo() reached its target {element, position}
scroll:cancel Animation cancelled mid-flight none
scroll:animationComplete Scroll animation finished {startY, targetY, duration}
scroll:direction Scroll direction changed {direction}
scroll:resize Observed container resized {entries, timestamp}
scroll:reveal data-scroll-reveal element entered viewport {element}
scroll:cleanup Resources released before teardown {timestamp, source}
section:active data-scroll-section entered viewport {id}
waypoint:trigger Waypoint entered viewport {id, entry}
touch:move Touch drag in progress {diffX, diffY, originalEvent}
EventManager.on('waypoint:trigger', (data) => {
  console.log(`${data.id} is now visible`);
});

Real-World Examples

<nav>
  <a href="#home">Home</a>
  <a href="#features">Features</a>
  <a href="#pricing">Pricing</a>
  <a href="#contact">Contact</a>
</nav>

<section id="home">...</section>
<section id="features">...</section>
<section id="pricing">...</section>
<section id="contact">...</section>

<script>
await ScrollManager.init({
  enabled: true,
  smoothScroll: {
    enabled: true,
    selector: 'a[href^="#"]'
  }
});
</script>

Back to Top Button

<button id="back-to-top" class="hidden">↑</button>

<script>
const button = document.getElementById('back-to-top');

// Show/hide based on scroll position
window.addEventListener('scroll', () => {
  button.classList.toggle('hidden', window.scrollY < 300);
});

button.addEventListener('click', () => {
  ScrollManager.scrollToTop({ duration: 400 });
});
</script>

Active Section Highlighting

const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('nav a');

sections.forEach(section => {
  ScrollManager.addWaypoint(section.id, section, {
    threshold: 0.3,
    onEnter: () => {
      navLinks.forEach(link => {
        link.classList.toggle('active',
          link.getAttribute('href') === `#${section.id}`
        );
      });
    }
  });
});

Lazy Load Images

const images = document.querySelectorAll('img[data-src]');

images.forEach((img, index) => {
  ScrollManager.addWaypoint(`lazy-${index}`, img, {
    threshold: 0.1,
    onEnter: () => {
      img.src = img.dataset.src;
      img.removeAttribute('data-src');
      ScrollManager.removeWaypoint(`lazy-${index}`);
    }
  });
});

Common Pitfalls

⚠️ 1. Wait for Init

// ❌ Using before init
ScrollManager.scrollTo('#section');

// ✅ Wait for init
await ScrollManager.init({ enabled: true });
ScrollManager.scrollTo('#section');

⚠️ 2. Offset for Fixed Header

// ❌ Not accounting for header
ScrollManager.scrollTo('#content');

// ✅ Add offset
const headerHeight = document.querySelector('header').offsetHeight;
ScrollManager.scrollTo('#content', {
  offset: -headerHeight
});