DEV Community

Justin Clark
Justin Clark

Posted on

Building Smooth Scrolling with react-scroll in React

react-scroll is a React library that provides smooth scrolling functionality, scroll spy, and animated scrolling to specific elements on a page. It's perfect for creating single-page applications with navigation menus, smooth scroll-to-section behavior, and scroll-based animations. This guide walks through setting up and implementing smooth scrolling using react-scroll with React, from installation to a working implementation.

Demo animation

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Basic knowledge of React hooks (useState, useEffect)
  • Familiarity with JavaScript/TypeScript
  • Understanding of DOM scrolling

Installation

Install react-scroll using your preferred package manager:

npm install react-scroll
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-scroll
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-scroll
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-scroll": "^1.9.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

react-scroll requires minimal setup. Import the components and use them in your application.

First Example / Basic Usage

Let's create a simple smooth scrolling navigation. Create a new file src/ScrollExample.jsx:

// src/ScrollExample.jsx
import React from 'react';
import { Link, Element } from 'react-scroll';

function ScrollExample() {
  return (
    <div>
      <nav style={{ position: 'fixed', top: 0, width: '100%', backgroundColor: '#fff', padding: '10px', zIndex: 1000 }}>
        <Link to="section1" smooth={true} duration={500}>
          Section 1
        </Link>
        {' '}
        <Link to="section2" smooth={true} duration={500}>
          Section 2
        </Link>
        {' '}
        <Link to="section3" smooth={true} duration={500}>
          Section 3
        </Link>
      </nav>
      <div style={{ marginTop: '60px' }}>
        <Element name="section1" style={{ height: '100vh', padding: '20px', backgroundColor: '#f0f0f0' }}>
          <h2>Section 1</h2>
          <p>This is the first section</p>
        </Element>
        <Element name="section2" style={{ height: '100vh', padding: '20px', backgroundColor: '#e0e0e0' }}>
          <h2>Section 2</h2>
          <p>This is the second section</p>
        </Element>
        <Element name="section3" style={{ height: '100vh', padding: '20px', backgroundColor: '#d0d0d0' }}>
          <h2>Section 3</h2>
          <p>This is the third section</p>
        </Element>
      </div>
    </div>
  );
}

export default ScrollExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import ScrollExample from './ScrollExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <ScrollExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates a navigation menu with smooth scrolling to different sections.

Understanding the Basics

react-scroll provides scrolling components:

  • Link: Component for triggering smooth scroll to an element
  • Element: Wrapper component that defines scrollable sections
  • animateScroll: Function for programmatic scrolling
  • scroller: Utility for scroll operations

Key concepts:

  • Smooth scrolling: Animated scroll to target elements
  • Scroll spy: Highlight active section in navigation
  • Element names: Use name prop to identify scroll targets
  • Duration: Control scroll animation speed
  • Offset: Adjust scroll position offset

Here's an example with scroll spy:

// src/AdvancedScrollExample.jsx
import React, { useState } from 'react';
import { Link, Element, scroller } from 'react-scroll';

function AdvancedScrollExample() {
  const [activeSection, setActiveSection] = useState('section1');

  const handleSetActive = (to) => {
    setActiveSection(to);
  };

  const scrollToTop = () => {
    scroller.scrollTo('section1', {
      smooth: true,
      duration: 500
    });
  };

  return (
    <div>
      <nav style={{ position: 'fixed', top: 0, width: '100%', backgroundColor: '#fff', padding: '10px', zIndex: 1000 }}>
        <Link 
          to="section1" 
          smooth={true} 
          duration={500}
          spy={true}
          onSetActive={handleSetActive}
          style={{ marginRight: '20px', color: activeSection === 'section1' ? '#007bff' : '#333' }}
        >
          Section 1
        </Link>
        <Link 
          to="section2" 
          smooth={true} 
          duration={500}
          spy={true}
          onSetActive={handleSetActive}
          style={{ marginRight: '20px', color: activeSection === 'section2' ? '#007bff' : '#333' }}
        >
          Section 2
        </Link>
        <Link 
          to="section3" 
          smooth={true} 
          duration={500}
          spy={true}
          onSetActive={handleSetActive}
          style={{ marginRight: '20px', color: activeSection === 'section3' ? '#007bff' : '#333' }}
        >
          Section 3
        </Link>
        <button onClick={scrollToTop} style={{ padding: '5px 10px' }}>
          Scroll to Top
        </button>
      </nav>
      <div style={{ marginTop: '60px' }}>
        <Element name="section1" style={{ height: '100vh', padding: '20px', backgroundColor: '#f0f0f0' }}>
          <h2>Section 1</h2>
          <p>This is the first section</p>
        </Element>
        <Element name="section2" style={{ height: '100vh', padding: '20px', backgroundColor: '#e0e0e0' }}>
          <h2>Section 2</h2>
          <p>This is the second section</p>
        </Element>
        <Element name="section3" style={{ height: '100vh', padding: '20px', backgroundColor: '#d0d0d0' }}>
          <h2>Section 3</h2>
          <p>This is the third section</p>
        </Element>
      </div>
    </div>
  );
}

export default AdvancedScrollExample;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a landing page with smooth scrolling navigation:

// src/LandingPage.jsx
import React, { useState } from 'react';
import { Link, Element } from 'react-scroll';

function LandingPage() {
  const [activeSection, setActiveSection] = useState('home');

  const sections = [
    { id: 'home', title: 'Home' },
    { id: 'about', title: 'About' },
    { id: 'services', title: 'Services' },
    { id: 'contact', title: 'Contact' }
  ];

  return (
    <div>
      <header style={{ 
        position: 'fixed', 
        top: 0, 
        width: '100%', 
        backgroundColor: '#fff', 
        padding: '15px 20px', 
        boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
        zIndex: 1000 
      }}>
        <nav style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ fontSize: '24px', fontWeight: 'bold' }}>MyApp</div>
          <div>
            {sections.map(section => (
              <Link
                key={section.id}
                to={section.id}
                smooth={true}
                duration={500}
                spy={true}
                onSetActive={() => setActiveSection(section.id)}
                style={{
                  marginLeft: '20px',
                  textDecoration: 'none',
                  color: activeSection === section.id ? '#007bff' : '#333',
                  fontWeight: activeSection === section.id ? 'bold' : 'normal',
                  cursor: 'pointer'
                }}
              >
                {section.title}
              </Link>
            ))}
          </div>
        </nav>
      </header>
      <div style={{ marginTop: '70px' }}>
        <Element name="home" style={{ height: '100vh', padding: '40px', backgroundColor: '#f8f9fa', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ textAlign: 'center' }}>
            <h1 style={{ fontSize: '48px', marginBottom: '20px' }}>Welcome to MyApp</h1>
            <p style={{ fontSize: '20px' }}>A modern React application</p>
          </div>
        </Element>
        <Element name="about" style={{ height: '100vh', padding: '40px', backgroundColor: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div>
            <h2 style={{ fontSize: '36px', marginBottom: '20px' }}>About Us</h2>
            <p style={{ fontSize: '18px', maxWidth: '600px' }}>
              We are a team of developers creating amazing React applications.
            </p>
          </div>
        </Element>
        <Element name="services" style={{ height: '100vh', padding: '40px', backgroundColor: '#f8f9fa', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div>
            <h2 style={{ fontSize: '36px', marginBottom: '20px' }}>Our Services</h2>
            <ul style={{ fontSize: '18px' }}>
              <li>Web Development</li>
              <li>Mobile Apps</li>
              <li>Consulting</li>
            </ul>
          </div>
        </Element>
        <Element name="contact" style={{ height: '100vh', padding: '40px', backgroundColor: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div>
            <h2 style={{ fontSize: '36px', marginBottom: '20px' }}>Contact Us</h2>
            <p style={{ fontSize: '18px' }}>Get in touch with us</p>
          </div>
        </Element>
      </div>
    </div>
  );
}

export default LandingPage;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import LandingPage from './LandingPage';
import './App.css';

function App() {
  return (
    <div className="App">
      <LandingPage />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Landing page navigation
  • Smooth scrolling between sections
  • Active section highlighting
  • Fixed navigation header
  • Scroll spy functionality
  • Professional layout

Common Issues / Troubleshooting

  1. Scrolling not working: Make sure Element components have unique name props that match Link to props. Check that elements are properly rendered in the DOM.

  2. Scroll position incorrect: Use offset prop to adjust scroll position. Check for fixed headers that might affect positioning.

  3. Scroll spy not updating: Ensure spy={true} and onSetActive handler are provided. Check that sections are properly sized and visible.

  4. Smooth scroll not smooth: Adjust duration prop for animation speed. Check browser compatibility for smooth scrolling.

  5. Links not clickable: Ensure Link components are properly rendered. Check for CSS that might be blocking clicks (pointer-events, z-index).

  6. Performance issues: For long pages, consider using offset to limit scroll distance. Optimize re-renders with React.memo if needed.

Next Steps

Now that you have an understanding of react-scroll:

  • Explore scroll animations
  • Learn about scroll events
  • Implement parallax effects
  • Add scroll progress indicators
  • Create scroll-triggered animations
  • Integrate with routing libraries
  • Check the official repository: https://github.com/fisshy/react-scroll

Summary

You've successfully set up react-scroll in your React application and created smooth scrolling navigation with scroll spy and animated transitions. react-scroll provides a powerful solution for building single-page applications with elegant navigation in React.

SEO Keywords

react-scroll
react-scroll smooth scroll
React smooth scrolling
react-scroll installation
React scroll navigation
react-scroll tutorial
React scroll spy
react-scroll example
React animated scroll
react-scroll setup
React scroll to element
react-scroll getting started
React single page navigation
react-scroll advanced usage

Top comments (0)