locomotive-scroll, react-scroll, scroll-behavior, and smooth-scroll are JavaScript libraries that help manage scrolling behavior in web applications, but they serve different purposes and operate at different levels of abstraction. smooth-scroll provides basic smooth scrolling to anchor links using native browser APIs with polyfills. react-scroll is a React-specific library for managing scroll positions and linking navigation to scrollable sections. locomotive-scroll offers advanced scroll-driven animations and custom scroll mechanics by hijacking the native scroll. scroll-behavior is a low-level utility focused on synchronizing scroll state across browser history entries, primarily used in routing contexts.
When building modern web experiences, controlling how users scroll — whether for aesthetics, usability, or interactivity — is often essential. The four packages under review address this need in fundamentally different ways: from lightweight polyfills to full scroll hijacking. Let’s examine their technical approaches, trade-offs, and real-world applicability.
smooth-scroll is a minimal, vanilla JavaScript utility that enables smooth scrolling to anchor links. It detects browser support for the CSS scroll-behavior: smooth property and falls back to manual animation when needed. It does not override native scrolling — it only enhances programmatic jumps.
// smooth-scroll: Basic usage
import SmoothScroll from 'smooth-scroll';
const scroll = new SmoothScroll('a[href*="#"]', {
speed: 500,
offset: 0
});
// Automatically handles clicks on anchor links
react-scroll is a React-specific library that provides components and hooks to manage scroll position within a React app. It works with native scrolling and focuses on linking UI elements (like navigation menus) to scrollable sections.
// react-scroll: Linking nav to sections
import { Link, Element } from 'react-scroll';
function App() {
return (
<>
<nav>
<Link to="section1" spy={true} smooth={true}>Section 1</Link>
</nav>
<Element name="section1">Content here</Element>
</>
);
}
locomotive-scroll takes a radically different approach: it disables native scrolling entirely and simulates scroll using CSS transforms on a container. This allows for precise control over scroll velocity, direction, and timing — enabling complex effects like horizontal scrolling, parallax layers, and scroll-triggered animations.
// locomotive-scroll: Full scroll hijacking
import LocomotiveScroll from 'locomotive-scroll';
const scroll = new LocomotiveScroll({
el: document.querySelector('[data-scroll-container]'),
smooth: true
});
// Requires specific markup: <div data-scroll-container><div data-scroll>...</div></div>
scroll-behavior was designed to solve a narrow problem: synchronizing scroll position with browser history during client-side navigation (e.g., in SPAs). However, it is deprecated and should not be used in new projects. Modern routers handle this natively.
// scroll-behavior: Deprecated pattern (do not use)
import { install } from 'scroll-behavior';
// This approach is obsolete — React Router v6 uses window.history.scrollRestoration
The biggest architectural divide is whether the library respects or replaces the browser’s native scroll mechanism.
smooth-scroll and react-scroll work on top of native scrolling. They trigger window.scrollTo() or element.scrollIntoView() with smooth behavior. This preserves accessibility (keyboard navigation, screen reader compatibility) and performance (browser-optimized rendering).
locomotive-scroll replaces native scrolling by applying transform: translate3d() to a container. This gives developers pixel-perfect control but breaks standard scroll behaviors: keyboard arrow keys don’t work, browser scrollbars disappear, and scroll-linked animations may jitter if not carefully optimized.
scroll-behavior attempted to patch native scroll restoration logic but is now irrelevant due to browser improvements.
All active packages support smooth scrolling to anchors, but with different ergonomics.
// smooth-scroll
new SmoothScroll('a[href*="#about"]');
// react-scroll (in JSX)
<Link to="about" smooth={true}>Go to About</Link>
// locomotive-scroll (requires manual API call)
scroll.scrollTo('#about');
// scroll-behavior — cannot do this; not its purpose
Only locomotive-scroll provides built-in support for scroll-linked effects via data attributes:
<!-- locomotive-scroll -->
<div data-scroll data-scroll-speed="2">Parallax element</div>
react-scroll and smooth-scroll offer no such features. You’d need to combine them with Intersection Observer or GSAP for animations.
react-scroll is purpose-built for React and provides hooks like useScroll() and components that respect React’s rendering cycle. The others are framework-agnostic:
// react-scroll: React-aware
const [activeSection, setActiveSection] = useState('home');
<Element name="home" onSetActive={() => setActiveSection('home')}>
Home content
</Element>
Using locomotive-scroll in React requires manual cleanup and DOM refs:
// locomotive-scroll in React (more boilerplate)
useEffect(() => {
const scroll = new LocomotiveScroll({ el: containerRef.current, smooth: true });
return () => scroll.destroy();
}, []);
Because smooth-scroll and react-scroll use native scrolling, they inherit browser optimizations and accessibility features. locomotive-scroll requires extra work to restore these:
The scroll-behavior package is officially deprecated. Its README states: "This project is no longer maintained." Modern solutions like React Router v6’s built-in scroll restoration (<ScrollRestoration />) or the native history.scrollRestoration = 'manual' API make it obsolete. Do not use it in new projects.
react-scrolllocomotive-scrollsmooth-scroll| Package | Scroll Model | Framework | Key Strength | Accessibility | Maintenance Status |
|---|---|---|---|---|---|
locomotive-scroll | Simulated (CSS) | Agnostic | Advanced scroll effects | Requires work | Active |
react-scroll | Native | React | Declarative section navigation | Good | Active |
scroll-behavior | Native (patch) | Agnostic | Scroll + history sync (obsolete) | N/A | Deprecated |
smooth-scroll | Native (polyfill) | Agnostic | Simple anchor smoothing | Good | Active |
smooth-scroll — it’s tiny and reliable.react-scroll gives you clean, component-driven control.locomotive-scroll is powerful but demands performance and accessibility diligence.scroll-behavior — it’s outdated and unnecessary in modern apps.Choose based on whether you need to enhance native scroll (smooth-scroll, react-scroll) or replace it (locomotive-scroll). Most projects fall into the first category — keep it simple unless you truly need custom scroll mechanics.
Choose locomotive-scroll if you need advanced scroll effects like parallax, pinned elements, or custom scroll physics that go beyond native browser capabilities. It’s ideal for highly designed, interactive storytelling sites where scroll is a core interaction mechanic. Be aware it disables native scroll and requires careful handling of performance and accessibility.
Choose react-scroll if you’re building a React application that needs section-based navigation (like a single-page site with a sticky nav) and want declarative, component-driven control over scroll behavior. It integrates well with React’s lifecycle and works on top of native scrolling, making it lightweight and accessible by default.
Do not use scroll-behavior in new projects — it is deprecated and no longer maintained. The package was designed to manage scroll restoration in router-aware applications but has been superseded by built-in browser features and modern router libraries like React Router v6, which handle scroll behavior natively.
Choose smooth-scroll if you only need basic smooth scrolling to anchor targets (e.g., jump links) without heavy dependencies or custom scroll hijacking. It uses the native scroll-behavior: smooth CSS property when available and falls back to JavaScript animation, making it simple, accessible, and performant for straightforward use cases.
A lightweight & modern scroll library for detection, animation, and smooth scrolling. Built on top of Lenis.
Full documentation available at scroll.locomotive.ca/docs.
npm install locomotive-scroll
import LocomotiveScroll from 'locomotive-scroll';
const scroll = new LocomotiveScroll();
@import 'locomotive-scroll/dist/locomotive-scroll.css';
<div data-scroll data-scroll-speed="0.5">I move at half speed</div>
Check out the examples and playground