Now.js Framework Documentation

Now.js Framework Documentation

ScrollManager

EN 15 Dec 2025 08:04

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

Events

Event When Triggered Detail
scroll:start Scroll animation starts {target}
scroll:end Scroll animation ends {position}
scroll:progress During scroll {progress}
waypoint:enter Element enters viewport {id, element}
waypoint:leave Element leaves viewport {id, element}
EventManager.on('waypoint:enter', (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
});