Scrolling to an element in React can be done using plain JavaScript.

You can select a DOM element and update the scrollable element's (e.g. body) scrollTop position manually, or using the scrollTo method to match the DOM element's top position on the screen. However, there's an easier way...

Using scrollIntoView function

The simplest way to scroll to an element in React is by calling the scrollIntoView function on the element. However, you first need to get the DOM element ref from useRef or select it from the DOM directly.

Here's how you might scroll to another section when clicking a button:

import './style.css';

function BasicExample() {
  const handleClickScroll = () => {
    const element = document.getElementById('section-1');
    if (element) {
      // πŸ‘‡ Will scroll smoothly to the top of the next section
      element.scrollIntoView({ behavior: 'smooth' });
    }
  };

  return (
    <>
      <div id="hero-section">
        <button className="btn-scroll" onClick={handleClickScroll}>
          Scroll Down
        </button>
      </div>
      <div id="section-1">Section 1</div>
    </>
  );
}

export default BasicExample;
Basic example of scrollIntoView usage in React

Here's what it looks like:

Additionally, the scrollIntoView method accepts optional parameters to control the scroll animation and where to focus on the element.


Real quick - would you like to master Web Development? If so, be sure to check out my recommended platform to learn coding online:

Learn Coding Online
Here’s the platform I recommend if you want to learn Web Development online.

Scroll to a new element in React

Because we require a referent to a DOM element to scroll it into view, we may run into problems when the DOM element is created in response to state changes in React.

An example of this problem is a list, where we want to scroll to the last element in the list after a new one is added, but the list is rendered based on an array in the state.

πŸ“£
If we try to immediately scroll down to the last element at the bottom, we'd be off by one because the new DOM element isn't yet rendered based on the updated state.

You can use the flushSync method from react-dom to update the DOM immediately after the component state is updated. Here's how it can be used:

import { useRef, useState } from 'react';
import { flushSync } from 'react-dom';
import { v4 as uuid } from 'uuid';
import { uniqueNamesGenerator, names } from 'unique-names-generator';
import './style.css';

type Person = {
  id: string;
  name: string;
};

function Example() {
  const listRef = useRef<HTMLUListElement | null>(null);
  const [people, setPeople] = useState<Person[]>([]);

  const handleAddClick = () => {
    // πŸ‘‡ Will wait until the DOM is updated with the new state
    flushSync(() => {
      setPeople((people) => [
        ...people,
        {
          id: uuid(),
          name: uniqueNamesGenerator({
            dictionaries: [names],
          }),
        },
      ]);
    });

    // πŸ‘‡ Scroll to the last element in the list
    listRef.current?.lastElementChild?.scrollIntoView();
  };

  return (
    <>
      <ul className="list" ref={listRef}>
        {people.map((person) => (
          <li key={person.id}>{person.name}</li>
        ))}
      </ul>
      <button onClick={handleAddClick}>Add new person</button>
    </>
  );
}

export default Example;
Using flushSync to immediately scroll to bottom after a new item is added in state.

Here's what the result looks like:

Scrolling to the newly added element in the list.

Scroll to element only if needed

The scrollIntoView method will scroll even if the element is already visible on the screen. You may not want it to do anything in that case. There is an alternative method with the same options called scrollIntoViewIfNeeded.

The scrollIntoViewIfNeeded option is still experimental without good support on Firefox. To achieve complete support, you can use a ponyfill.

Caveat

By using scrollIntoView (and also scrollTo) with behavior: smooth you're leaving it up to the browser to control the animation. This means smooth scrolling may not work with some browser or OS settings.

The "Animate controls and elements in windows" option

I've noticed, that if I uncheck the "Animate controls and elements in windows" box in my Windows Performance Options, the smooth scrolling stops working across all browsers.

To gain more control you may use a 3rd party scroll-into-view library, which will also give you additional options to fine-tune the scroll behavior.

Conclusion

JavaScript API offers a simple way to scroll to an element via scrollIntoView method. However, it doesn't offer much fine-grained control and depends on browser and OS settings.

If you're willing to put a little more effort, you can use a 3rd party library that allows you to tweak the settings to your liking. It works by manually updating the scrollTop position, so it's unaffected by the environment settings.


Hey, if you're serious about learning React, I highly recommend the courses on educative.io - it's my favorite platform for learning to code.

Here's a course on React that will teach you how to build something more than another to-do app (finally, am I right?):

React for Front-End Developers - Learn Interactively
Backed by Facebook and used by tech companies large and small, React has quickly become the most popular front-end framework in the tech world. Its developers are constantly in high demand. If you’re already familiar with JavaScript, adding React to your skillset is a wise career investment. This p…