How to create a React scroll-to-top button
Learn how to create a simple scroll-to-top button with React to allow your users to quickly jump to the top of a webpage with just a click of a button.
A lot of sites, including this one for some time, don't have an easy way for their users to get back to the top of the page. Sure, the user could manually scroll, but this can be frustrating, especially on really long pages.
That's why a button, usually positioned in the bottom-right of the page, that allows users to get back to the top of the page in a single click is useful.
Watch the lesson
Project repo
The code for this project is open-source and available on GitHub. I use Gumroad for those that want to be generous and donate, but no purchase is required. π
Next.js and Tailwind CSS starter
In this project, I'm using Next.js and Tailwind CSS, but at the end of the day all we're doing is creating a React component. Feel free to use Next.js, Gatsby, Create React App, or whatever library or starter you want. The core concepts are the same as long as you're building with React.
Styling your component is also up to your project preferences. I've been enjoying Tailwind CSS lately and use it in this lesson, but feel free to use any CSS solution you want. Check out the Tailwind installation guide if you're interested in using Tailwind for your project.
ScrollToTop component
Start by creating a new component named ScrollToTop.js
and write the following code:
import { useEffect, useState } from 'react'import { BiArrowFromBottom } from 'react-icons/bi'import { classNames } from '/utils'export const ScrollToTop = () => {const [isVisible, setIsVisible] = useState(false)const toggleVisibility = () => {if (window.pageYOffset > 300) {setIsVisible(true)} else {setIsVisible(false)}}const scrollToTop = () => {window.scrollTo({top: 0,behavior: 'smooth',})}useEffect(() => {window.addEventListener('scroll', toggleVisibility)return () => {window.removeEventListener('scroll', toggleVisibility)}}, [])return (<div className="fixed bottom-2 right-2"><buttontype="button"onClick={scrollToTop}className={classNames(isVisible ? 'opacity-100' : 'opacity-0','bg-pink-600 hover:bg-pink-700 focus:ring-pink-500 inline-flex items-center rounded-full p-3 text-white shadow-sm transition-opacity focus:outline-none focus:ring-2 focus:ring-offset-2',)}><BiArrowFromBottom className="h-6 w-6" aria-hidden="true" /></button></div>)}
React useEffect and useState hooks
You start by importing useEffect
and useState
hooks from React. The useEffect
hook will be used to handle side effects in the component and the useState
hook will be used to create a isVisible
state value and setIsVisible
state function. You can learn more about these hooks from the useState guide and useEffect guide.
React icons
The next import is from React icons, an optional package that includes a variety of free icon components. The one we're using in this component comes from the Box Icons set.
className utility function
The classNames
function is a simple utility function that we'll use to join Tailwind CSS classnames:
export const classNames = (...classes) => {return classes.filter(Boolean).join(' ')}
The first thing this function does is to check that the item passed in from the array is truthy. Michael Uloth wrote a great post on how the filter(Boolean) trick works in JavaScript in case you want to learn more.
Next, it uses join(' ')
to combine all the values in the array with a space so the className
is correctly formatted.
useState hook
Inside the actual component, you start by creating a new state value and state function using the useState
React hook. The state value is isVisible
and the function used to update the state value is setIsVisible
. You can call these whatever you want, but it's a good idea to stick to a similar naming convention so your state values are easy to read.
toggleVisibility function
The toggleVisibility
function uses the window interface to check if the user's vertical scroll position is great than 300. If true the function will set the isVisible
state to true
. Else, it will set the isVisible
state to false
.
scrollToTop
The scrollToTop
function also uses the window interface, but this time it's using a method called scrollTo
. This method takes X and Y coordinates as arguments or an option arguement where you can pass in position values and a behavior
value. By default the browser will automatically jump to the top of the page, but with behavior: 'smooth'
the user will experience a smooth scroll transition.
useEffect hook
In the useEffect
hook you use the addEventListener
method to add an event listener on the window interface that listens for scroll events. If a scroll event is triggered it will fire the toggleVisibility
function.
Any time you add an event listener you also need to tell the component to stop listening for the events in the cleanup function. To do that you used the removeEventListener
method on the window interface. It's important to add this cleanup function to avoid memory leak issues and errors in React.
Component return
This part of the code is the button HTML and CSS styles. You'll notice that the classNames
utility function is being used to combine the return value from a ternary operator with some other general Tailwind CSS classnames.
The ternary operator is being used to add conditional styles to control the button's opacity depending if the isVisible
state value is true
or false
.
Using the button
With the ScrollToTop
component completed you can now use it on any page you want. For example, you can add it to index.js
page like so:
import { ScrollToTop } from '/components'export default function Home() {return (<><ScrollToTop />{/* Lots of content */}</>)}
Conclusion
It's a nice touch to add a scroll-to-top button to any long page in your React application. It saves your user some time from having to scroll manually, plus it's really simple to implement using the window interface, basic CSS, and a couple React Hooks.