use-smart-scroll
TypeScript icon, indicating that this package has built-in type declarations

3.0.2 • Public • Published

use-smart-scroll

use-smart-scroll

npm downloads bundle size TypeScript License: MIT

A comprehensive collection of React hooks and utilities for smart scroll handling, animations, and interactions.

✓ Features

  • 10+ Smart Hooks - Complete scroll state management
  • Smooth Scrolling - 20+ easing functions for perfect animations
  • Scroll Spy - Track visible elements and active sections
  • Infinite Scroll - Easy infinite scrolling implementation
  • Scroll Lock - Prevent body scrolling (modals, overlays)
  • Parallax Effects - Smooth parallax scrolling
  • Scroll Animations - Trigger animations on scroll
  • Mobile Optimized - Touch-friendly and performant
  • Highly Configurable - Extensive customization options
  • TypeScript Support - Full type definitions included
  • Lightweight - Tree-shakeable, minimal bundle impact
  • Performance First - RAF, throttling, and debouncing built-in

📦 Installation

npm install use-smart-scroll
# or
bun add use-smart-scroll
# or
yarn add use-smart-scroll
# or
pnpm add use-smart-scroll

✓ Quick Start

import React from 'react';
import { useScroll, useSmoothScroll } from 'use-smart-scroll';

function App() {
  const { show, scrolled, direction, isAtTop } = useScroll();
  const { scrollToTop, scrollToElement } = useSmoothScroll();

  return (
    <div>
      {/* Smart Navigation */}
      <nav className={`navbar ${show ? 'visible' : 'hidden'} ${scrolled ? 'scrolled' : ''}`}>
        <button onClick={() => scrollToElement('#about', { duration: 800 })}>
          About
        </button>
        <button onClick={() => scrollToTop()} disabled={isAtTop}>
          Back to Top
        </button>
      </nav>
      
      {/* Discount Banner - Only at top */}
      {isAtTop && (
        <div className="discount-banner">
          🎉 Special Offer: 50% OFF! Use code: SAVE50
        </div>
      )}
      
      <main>
        <section id="hero">Hero Section</section>
        <section id="about">About Section</section>
      </main>
    </div>
  );
}

📚 Smart Hooks Overview

🎯 Core Hooks

Hook Purpose Returns
useScroll Complete scroll state { show, scrolled, direction, position, velocity, isAtTop, isAtBottom }
useSmoothScroll Smooth scrolling utilities { scrollTo, scrollToTop, scrollToElement, cancel }
useScrollSpy Track visible elements { activeElement, visibleElements }
useScrollProgress Scroll progress percentage progress (0-100)

🎨 Advanced Hooks

Hook Purpose Use Case
useInfiniteScroll Infinite loading Social feeds, product lists
useScrollLock Prevent scrolling Modals, overlays
useParallax Parallax effects Hero sections, backgrounds
useScrollAnimation Scroll-triggered animations Fade-ins, reveals

📖 Detailed API

useScroll(options?)

The main smart hook that provides comprehensive scroll state information.

const {
  show,           // boolean - show/hide based on scroll direction
  scrolled,       // boolean - scrolled past threshold
  scrollY,        // number - current Y position
  scrollX,        // number - current X position
  direction,      // { vertical: 'up'|'down'|'none', horizontal: 'left'|'right'|'none' }
  velocity,       // number - scroll velocity
  isScrolling,    // boolean - currently scrolling
  isAtTop,        // boolean - at top of page
  isAtBottom,     // boolean - at bottom of page
  isAtLeft,       // boolean - at left edge
  isAtRight,      // boolean - at right edge
} = useScroll({
  directionThreshold: 0,     // threshold for direction detection
  scrolledThreshold: 100,    // threshold for scrolled state
  throttle: 100,             // throttle scroll events (ms)
  debounce: 0,               // debounce scroll events (ms)
  onScroll: (state) => {},   // callback on scroll
});

Example: Smart Navigation with Discount Banner

function SmartNavigation() {
  const { show, scrolled, direction, isAtTop } = useScroll({
    scrolledThreshold: 50,
    throttle: 16, // 60fps
  });
  
  return (
    <>
      {/* Discount Banner - Only at top */}
      <div className={`
        fixed top-0 left-0 right-0 z-50 bg-red-500 text-white text-center py-2
        transition-all duration-300 transform
        ${isAtTop ? 'translate-y-0 opacity-100' : '-translate-y-full opacity-0'}
      `}>
        🎉 Special Offer: 50% OFF! Use code: SAVE50
      </div>

      {/* Smart Navigation */}
      <nav className={`
        fixed left-0 right-0 z-40 transition-all duration-300
        ${isAtTop ? 'top-10' : 'top-0'}
        ${show ? 'translate-y-0' : '-translate-y-full'}
        ${scrolled ? 'bg-white shadow-lg' : 'bg-transparent'}
      `}>
        <div className="flex justify-between items-center p-4">
          <div>Logo</div>
          <div className="text-sm">
            Direction: {direction.vertical}
          </div>
        </div>
      </nav>
    </>
  );
}

useSmoothScroll()

Provides smart smooth scrolling utilities with customizable easing functions.

const {
  scrollTo,           // (options) => Promise<void>
  scrollToTop,        // (duration?) => Promise<void>
  scrollToBottom,     // (duration?) => Promise<void>
  scrollToElement,    // (element, options?) => Promise<void>
  scrollIntoView,     // (element, options?) => Promise<void>
  cancel,             // () => void
  isScrolling,        // () => boolean
} = useSmoothScroll();

Example: Smart Navigation Menu

function SmartNavigationMenu() {
  const { scrollToElement } = useSmoothScroll();
  const { activeElement } = useScrollSpy(['#home', '#about', '#contact']);
  
  const menuItems = [
    { id: '#home', label: 'Home' },
    { id: '#about', label: 'About' },
    { id: '#contact', label: 'Contact' },
  ];
  
  return (
    <nav className="flex space-x-4">
      {menuItems.map(({ id, label }) => (
        <button
          key={id}
          onClick={() => scrollToElement(id, {
            duration: 800,
            easing: 'easeInOutCubic',
            offset: -100,
            onComplete: () => console.log('Scrolled to', label),
          })}
          className={`px-4 py-2 rounded transition-colors ${
            activeElement === id 
              ? 'bg-blue-500 text-white' 
              : 'text-gray-600 hover:text-blue-500'
          }`}
        >
          {label}
        </button>
      ))}
    </nav>
  );
}

Smart Scroll Options:

await scrollTo({
  target: 1000,                    // scroll position or element
  duration: 800,                  // animation duration
  easing: 'easeInOutCubic',       // easing function
  offset: -100,                   // offset from target
  onStart: () => console.log('Started'),
  onComplete: () => console.log('Completed'),
  onCancel: () => console.log('Cancelled'),
});

useScrollSpy(elements, options?)

Smart tracking of which elements are currently visible in the viewport.

const { activeElement, visibleElements } = useScrollSpy(
  ['#section1', '#section2', '#section3'],
  {
    offset: 100,           // offset from top
    threshold: 0.5,        // visibility threshold (0-1)
    rootMargin: '0px',     // intersection observer margin
  }
);

useScrollProgress()

Get the current scroll progress as a percentage with smart calculation.

const progress = useScrollProgress(); // 0-100

Example: Smart Reading Progress Bar

function SmartReadingProgress() {
  const progress = useScrollProgress();
  
  return (
    <div className="fixed top-0 left-0 w-full h-1 bg-gray-200 z-50">
      <div 
        className="h-full bg-gradient-to-r from-blue-500 to-purple-600 transition-all duration-150"
        style={{ width: `${progress}%` }}
      />
    </div>
  );
}

useInfiniteScroll(options)

Smart infinite scrolling with loading states and error handling.

const { setTarget, isLoading } = useInfiniteScroll({
  hasMore: true,                    // has more items to load
  onLoadMore: async () => {         // load more function
    await fetchMoreItems();
  },
  threshold: 100,                   // distance from bottom to trigger
  rootMargin: '100px',             // trigger area
});

Example: Smart Product List

function SmartProductList() {
  const [products, setProducts] = useState([]);
  const [hasMore, setHasMore] = useState(true);
  const [loading, setLoading] = useState(false);
  
  const { setTarget } = useInfiniteScroll({
    hasMore,
    onLoadMore: async () => {
      setLoading(true);
      try {
        const newProducts = await fetchProducts();
        setProducts(prev => [...prev, ...newProducts]);
        if (newProducts.length === 0) setHasMore(false);
      } catch (error) {
        console.error('Failed to load products:', error);
      } finally {
        setLoading(false);
      }
    },
  });
  
  return (
    <div className="space-y-4">
      {products.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
      
      {hasMore && (
        <div ref={setTarget} className="p-8 text-center">
          {loading ? (
            <>
              <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto"></div>
              <p className="mt-2 text-gray-600">Loading more products...</p>
            </>
          ) : (
            <p className="text-gray-500">Scroll to load more</p>
          )}
        </div>
      )}
      
      {!hasMore && (
        <div className="text-center p-8">
          <p className="text-gray-600">🎉 You've seen all products!</p>
        </div>
      )}
    </div>
  );
}

useScrollLock(options?)

Smart scroll locking for modals and overlays with mobile support.

const { lock, unlock, toggle, isLocked } = useScrollLock({
  reserveScrollBarGap: true,        // maintain scrollbar space
  allowTouchMove: (el) => false,    // allow touch move on specific elements
});

Example: Smart Modal with Scroll Lock

function SmartModal({ isOpen, onClose, children }) {
  const { lock, unlock, isLocked } = useScrollLock();
  
  useEffect(() => {
    if (isOpen) {
      lock();
    } else {
      unlock();
    }
    
    return () => unlock(); // cleanup
  }, [isOpen, lock, unlock]);
  
  if (!isOpen) return null;
  
  return (
    <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-2xl p-6 max-w-md w-full transform animate-fade-in-up">
        <div className="flex justify-between items-center mb-4">
          <h3 className="text-xl font-bold">Modal Title</h3>
          <button 
            onClick={onClose}
            className="text-gray-500 hover:text-gray-700 text-2xl"
          >
            ×
          </button>
        </div>
        {children}
        <div className="mt-4 text-sm text-gray-500">
          Scroll Lock: {isLocked ? 'Active' : 'Inactive'}
        </div>
      </div>
    </div>
  );
}

useParallax(options?)

Create smart parallax scrolling effects with performance optimization.

const parallaxRef = useParallax({
  speed: 0.5,          // parallax speed (0-1)
  offset: 0,           // initial offset
  min: -100,           // minimum transform value
  max: 100,            // maximum transform value
});

Example: Smart Hero Section

function SmartHeroSection() {
  const parallaxRef = useParallax({ speed: 0.5 });
  const { scrollY } = useScroll();
  
  return (
    <section className="relative h-screen overflow-hidden">
      <div 
        ref={parallaxRef}
        className="absolute inset-0 bg-cover bg-center"
        style={{
          backgroundImage: 'url("/hero-bg.jpg")',
        }}
      />
      <div className="relative z-10 flex items-center justify-center h-full bg-black/30">
        <div className="text-center text-white">
          <h1 className="text-6xl font-bold mb-4">Smart Scrolling</h1>
          <p className="text-xl mb-8">Experience the power of use-smart-scroll</p>
          <div className="text-sm opacity-75">
            Scroll Position: {scrollY}px
          </div>
        </div>
      </div>
    </section>
  );
}

useScrollAnimation(options?)

Smart scroll-triggered animations with intersection observer.

const { elementRef, reset } = useScrollAnimation({
  threshold: 0.1,                   // intersection threshold
  triggerOnce: true,                // trigger only once
  animationClass: 'fade-in',        // CSS class to add
  animationDelay: 200,              // delay before animation
});

Example: Smart Animated Cards

function SmartAnimatedCard({ children, delay = 0 }) {
  const { elementRef } = useScrollAnimation({
    animationClass: 'animate-fade-in-up',
    threshold: 0.2,
    animationDelay: delay,
  });
  
  return (
    <div ref={elementRef} className="opacity-0 transform translate-y-8">
      {children}
    </div>
  );
}

function SmartFeatureSection() {
  return (
    <section className="py-20 bg-gray-50">
      <div className="max-w-6xl mx-auto px-4">
        <h2 className="text-4xl font-bold text-center mb-16">Smart Features</h2>
        <div className="grid md:grid-cols-3 gap-8">
          <SmartAnimatedCard delay={0}>
            <div className="bg-white p-6 rounded-xl shadow-lg">
              <h3 className="text-xl font-bold mb-4">🚀 Performance</h3>
              <p>Optimized with RAF and throttling</p>
            </div>
          </SmartAnimatedCard>
          
          <SmartAnimatedCard delay={200}>
            <div className="bg-white p-6 rounded-xl shadow-lg">
              <h3 className="text-xl font-bold mb-4">📱 Mobile First</h3>
              <p>Touch-friendly and responsive</p>
            </div>
          </SmartAnimatedCard>
          
          <SmartAnimatedCard delay={400}>
            <div className="bg-white p-6 rounded-xl shadow-lg">
              <h3 className="text-xl font-bold mb-4">🎯 TypeScript</h3>
              <p>Full type safety included</p>
            </div>
          </SmartAnimatedCard>
        </div>
      </div>
    </section>
  );
}

// CSS
.animate-fade-in-up {
  animation: fadeInUp 0.6s ease-out forwards;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

🎨 Smart Easing Functions

Available easing functions for smooth scrolling:

Basic

  • linear
  • easeInQuad, easeOutQuad, easeInOutQuad

Cubic

  • easeInCubic, easeOutCubic, easeInOutCubic

Advanced

  • easeInQuart, easeOutQuart, easeInOutQuart
  • easeInQuint, easeOutQuint, easeInOutQuint
  • easeInSine, easeOutSine, easeInOutSine
  • easeInExpo, easeOutExpo, easeInOutExpo
  • easeInCirc, easeOutCirc, easeInOutCirc
  • easeInBack, easeOutBack, easeInOutBack
  • easeInElastic, easeOutElastic, easeInOutElastic
  • easeInBounce, easeOutBounce, easeInOutBounce

🛠️ Utility Functions

import {
  // Scroll Control
  scrollTo,
  scrollToTop,
  scrollToBottom,
  scrollToElement,
  scrollIntoView,
  cancelScroll,
  
  // Position & Measurement
  getScrollPosition,
  getDocumentDimensions,
  getViewportDimensions,
  getElementOffset,
  getScrollProgress,
  
  // Detection & Validation
  isElementInViewport,
  isScrollable,
  getScrollableParent,
  
  // Performance
  throttle,
  debounce,
  rafThrottle,
  calculateVelocity,
  preventScroll,
  getScrollbarWidth,
} from 'use-smart-scroll';

🎯 Real-world Examples

E-commerce Website

import { useScroll, useInfiniteScroll, useScrollSpy, useSmoothScroll } from 'use-smart-scroll';

function EcommerceApp() {
  const { show, scrolled, isAtTop } = useScroll();
  const { scrollToTop } = useSmoothScroll();
  
  return (
    <div>
      {/* Discount Banner */}
      {isAtTop && (
        <div className="bg-red-500 text-white text-center py-2">
          🔥 Flash Sale: 70% OFF Everything!
        </div>
      )}
      
      {/* Smart Navigation */}
      <nav className={`sticky top-0 z-40 transition-all ${
        show ? 'translate-y-0' : '-translate-y-full'
      } ${scrolled ? 'bg-white shadow-lg' : 'bg-transparent'}`}>
        <div className="flex justify-between items-center p-4">
          <div>🛍️ Smart Store</div>
          <div className="flex space-x-4">
            <a href="#products">Products</a>
            <a href="#about">About</a>
            <button onClick={() => scrollToTop()}>🔝</button>
          </div>
        </div>
      </nav>
      
      {/* Product Grid with Infinite Scroll */}
      <ProductGrid />
    </div>
  );
}

Blog/News Website

function BlogApp() {
  const progress = useScrollProgress();
  const { activeElement } = useScrollSpy(['#intro', '#content', '#conclusion']);
  
  return (
    <div>
      {/* Reading Progress */}
      <div className="fixed top-0 w-full h-1 bg-gray-200 z-50">
        <div 
          className="h-full bg-blue-500 transition-all"
          style={{ width: `${progress}%` }}
        />
      </div>
      
      {/* Table of Contents */}
      <nav className="fixed left-4 top-1/2 transform -translate-y-1/2">
        {['intro', 'content', 'conclusion'].map(section => (
          <div key={section} className={`w-2 h-8 mb-2 rounded ${
            activeElement === `#${section}` ? 'bg-blue-500' : 'bg-gray-300'
          }`} />
        ))}
      </nav>
      
      <article>
        <section id="intro">Introduction</section>
        <section id="content">Main Content</section>
        <section id="conclusion">Conclusion</section>
      </article>
    </div>
  );
}

Landing Page

function LandingPage() {
  const { show, direction } = useScroll();
  const { scrollToElement } = useSmoothScroll();
  const parallaxRef = useParallax({ speed: 0.3 });
  
  return (
    <div>
      {/* Hero with Parallax */}
      <section className="relative h-screen overflow-hidden">
        <div ref={parallaxRef} className="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-600" />
        <div className="relative z-10 flex items-center justify-center h-full text-white">
          <div className="text-center">
            <h1 className="text-6xl font-bold mb-8">use-smart-scroll</h1>
            <p className="text-xl mb-8">Smart scrolling for modern React apps</p>
            <button 
              onClick={() => scrollToElement('#features', { duration: 1000 })}
              className="bg-white text-blue-500 px-8 py-3 rounded-full font-semibold hover:bg-gray-100"
            >
              Explore Features
            </button>
          </div>
        </div>
      </section>
      
      {/* Smart Navigation */}
      <nav className={`fixed top-0 w-full z-40 transition-all duration-300 ${
        show ? 'translate-y-0' : '-translate-y-full'
      } bg-white/90 backdrop-blur-md shadow-lg`}>
        <div className="flex justify-center space-x-8 p-4">
          <button onClick={() => scrollToElement('#hero')}>Home</button>
          <button onClick={() => scrollToElement('#features')}>Features</button>
          <button onClick={() => scrollToElement('#examples')}>Examples</button>
          <button onClick={() => scrollToElement('#contact')}>Contact</button>
        </div>
      </nav>
      
      {/* Animated Features */}
      <SmartFeatureSection />
    </div>
  );
}

📱 Mobile Optimization

// Mobile-specific configurations
const { show, scrolled } = useScroll({
  throttle: 16,              // 60fps for smooth mobile
  directionThreshold: 10,    // Larger threshold for touch
});

// Touch-friendly scroll lock
const { lock, unlock } = useScrollLock({
  allowTouchMove: (el) => {
    // Allow scrolling inside specific elements
    return el.closest('.scrollable-content') !== null;
  },
});

// Mobile-optimized infinite scroll
const { setTarget } = useInfiniteScroll({
  threshold: 200,            // Larger threshold for mobile
  rootMargin: '200px',       // Preload earlier on mobile
});

⚡ Performance Tips

1. Optimize Throttling

// For 60fps smooth performance
const { show } = useScroll({ throttle: 16 });

// For battery saving
const { show } = useScroll({ throttle: 100 });

2. Use Debouncing for Heavy Operations

const { scrollY } = useScroll({
  debounce: 300,
  onScroll: (state) => {
    // Heavy operations here
    updateAnalytics(state);
  },
});

3. Optimize Scroll Spy

// Use larger thresholds for better performance
const { activeElement } = useScrollSpy(elements, {
  threshold: 0.5,
  rootMargin: '100px',
});

🔧 Configuration

Global Configuration

// Create a custom hook with your defaults
function useAppScroll(options = {}) {
  return useScroll({
    throttle: 16,
    scrolledThreshold: 100,
    ...options,
  });
}

TypeScript Configuration

import type { 
  ScrollState, 
  ScrollToOptions, 
  UseScrollOptions 
} from 'use-smart-scroll';

// Custom scroll handler
const handleScroll = (state: ScrollState) => {
  console.log('Scroll state:', state);
};

// Custom scroll options
const scrollOptions: ScrollToOptions = {
  duration: 800,
  easing: 'easeInOutCubic',
  offset: -100,
};

🧪 Testing

import { renderHook, act } from '@testing-library/react';
import { useScroll } from 'use-smart-scroll';

test('should detect scroll direction', () => {
  const { result } = renderHook(() => useScroll());
  
  act(() => {
    // Simulate scroll
    Object.defineProperty(window, 'scrollY', { value: 100 });
    window.dispatchEvent(new Event('scroll'));
  });
  
  expect(result.current.direction.vertical).toBe('down');
});

📄 License

MIT © Eyachir Arafat

🙏 Acknowledgments

  • Inspired by modern scroll libraries
  • Built with performance and accessibility in mind
  • Community feedback

📞 Support


Made with ❤️ for the React community

⭐ Star on GitHub📦 View on NPM

Package Sidebar

Install

npm i use-smart-scroll

Weekly Downloads

28

Version

3.0.2

License

MIT

Unpacked Size

225 kB

Total Files

8

Last publish

Collaborators

  • eyachirarafat