DEV Community

loading...
Cover image for Scroll-to-top Button in vanilla JS (Beginners)

Scroll-to-top Button in vanilla JS (Beginners)

ljcdev profile image ljc-dev Updated on ・4 min read

Scroll to top button is a very common UX feature in websites. It's goal is to prevent annoying users forced to scroll back up - especially on mobile devices. In this short tutorial, we'll see how to implement one with css and pure (vanilla) javascript.

The simplest way to get a scroll to top button is to have an html element at the top and a link near the end of your page that calls it:

<div id="scroll-to-top"></div>
<!-- ... -->
<a href="#scroll-to-top"></a>
Enter fullscreen mode Exit fullscreen mode

And this css to make the scroll smooth:

html {
  scroll-behavior: "smooth";
}
Enter fullscreen mode Exit fullscreen mode

That's the easiest way to get a scroll to top (I've actually missed this on my original post as Loouis Low pointed out in the comments.)

Result here:

No javascript needed!

Scroll to top button with vanilla js

The previous example works fine but has a serious drawback because after clicking on that link, the anchor #scroll-to-top will show up in the url . We could call the anchor #home. But it'll still be in the url history when the user clicks back.

That's why I prefer to do it in js 😁. Plus js allows much more customization like:

  • Show button after the user has scrolled down x % of the page.
  • Animate entrance and leave.

The button

Let's just created a simple button with a class of scrollToTopBtn so we can refer to it in js.

<button class="scrollToTopBtn">TOP</button>
Enter fullscreen mode Exit fullscreen mode

Here are a few CSS properties for the button:

  • position: fixed; gets it out of the flow of the page.

  • bottom: 50px; and right: 50px; places it at the bottom right corner.

  • z-index: 100; a large z-index keeps the button on top of every other elements.

  • display: none; is used to hide it at first.

Detect user scroll

we can detect user's scroll with a scroll event listener:

document.addEventListener("scroll", handleScroll);

function handleScroll() {
  // do something on scroll
}
Enter fullscreen mode Exit fullscreen mode

Show the Scroll to Top button logic

In the handleScroll function, we'll check whether we need to show or hide the button. We are going to use three element properties:

  • clientHeight gives us the visible part of an element in its parent.

  • scrollHeight gives the total height of an element including the overflow part.

clientHeight and scrollHeight

The height of the overflow part is the total amount of pixels that can be scrolled. In other words: scrollableHeight = scrollHeight - clientHeight

var scrollableHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
Enter fullscreen mode Exit fullscreen mode

document.documentElement is the document element. We are using it instead of document because scrollHeight and clientHeight are elements' properties.

  • scrollTop gives the number of pixels scrolled from the top. It's the amount of pixels scrolled by the user.

By dividing scrollTop with scrollableHeight we get a ratio between 0 and 1. 0 meaning the user hasn't scrolled and 1 meaning the user scrolled to the end of the page. This ratio tells us how much the user scrolled.

If we want the scroll to top button to show up after the user scrolled 50% we set a golden ratio of 0.5. And, with an if else statement, make the button visible above and hidden below.

document.addEventListener("scroll", handleScroll);
// get a reference to the button
var scrollToTopBtn = document.querySelector(".scrollToTopBtn");

function handleScroll() {
  var scrollableHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
  var GOLDEN_RATIO = 0.5;

  if ((document.documentElement.scrollTop / scrollableHeight ) > GOLDEN_RATIO) {
    //show button
    scrollToTopBtn.style.display = "block";
  } else {
    //hide button
    scrollToTopBtn.style.display = "none";
  }
}
Enter fullscreen mode Exit fullscreen mode

With that the scroll-to-top button appears and hides on scroll.

Scroll to top

There a lot of scrolling examples that use jQuery. But these days it is really easy to do this in pure js with scrollTo:

\\...
scrollToTopBtn.addEventListener("click", scrollToTop);

function scrollToTop() {
  window.scrollTo({
    top: 0,
    behavior: "smooth"
  });
}
Enter fullscreen mode Exit fullscreen mode
  • top: 0, means scroll to 0px vertically.
  • behavior: "smooth" makes the scroll smooth.
  • there's also a left property for horizontal scroll.

And that's it! Here's the final js:

document.addEventListener("scroll", handleScroll);
// get a reference to our predefined button
var scrollToTopBtn = document.querySelector(".scrollToTopBtn");

function handleScroll() {
  var scrollableHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
  var GOLDEN_RATIO = 0.5;

  if ((document.documentElement.scrollTop / scrollableHeight ) > GOLDEN_RATIO) {
    //show button
    scrollToTopBtn.style.display = "block";
  } else {
    //hide button
    scrollToTopBtn.style.display = "none";
  }
}

scrollToTopBtn.addEventListener("click", scrollToTop);

function scrollToTop() {
  window.scrollTo({
    top: 0,
    behavior: "smooth"
  });
}
Enter fullscreen mode Exit fullscreen mode

Tada 🎉🎉🎉!

Thanks for reading 🥰🥰!! I hope this was of help.

Improvements:

I've tried to keep it simple. Usually I would also toggle a class instead of the display to show a transition animation.

Here's how you could fade up the button:

Discussion (15)

pic
Editor guide
Collapse
loouislow profile image
Loouis Low • Edited

The most minimalist scroll-to-top. (Rookie)

<!-- HTML -->
<div id="scroll-to-top">
  ...
</div>

<a href="#scroll-to-top">
  Scroll To Top
</a>
/* CSS */
body {
  scroll-behaviour: smooth
}
Collapse
ljcdev profile image
ljc-dev Author

Thanks for the feedback Loouis 😄!! This is indeed a minimal scroll to top implementation. It's perfect for rookies like u said.
I just want to note that scroll-behavior support is still not optimal caniuse.com/#search=scroll-behavior
And I was thinking of a button that would only appear after a certain amount of scroll and that is not attached to the flow of the page.
But thanks for the insight, I didn't think of this method 😁. Those who want to have a scroll to top with no js would love it!

Collapse
corentinbettiol profile image
Corentin Bettiol

Why using javascript when you can use only html and css ?

Collapse
ljcdev profile image
ljc-dev Author

Salut Corentin, maybe because I don't know yet how to do it without js 😅😅. But I'll look up on that. Thx for leaving a comment!

Collapse
corentinbettiol profile image
Corentin Bettiol • Edited

No problem :)

Smooth scroll (example here) is not yet implemented in Safari and some mobiles browsers, so it must be a good reason to keep using js for a couple more months.

Collapse
coryrunn profile image
Cory

Nice, thanks for sharing! I was recently wondering about adding a "scroll to top" button on my portfolio site vs. making my header "sticky". On the one hand, it would be nice to add some JS to my site to show that I can incorporate it, but on the other hand, using a sticky header would probably be better performance-wise (which may not matter on my simple portfolio website).

What do you think?

Collapse
ljcdev profile image
ljc-dev Author

Hey Cory, thanks for reading 😄!! You can definitely use both. I kinda understand why you you want to choose between them. Having a sticky header might make a scroll to top button a bit redundant. But I believe it's ok to use them together especially if the page is kinda long. And btw, I don't think this would create a performance issue. Let's chat on Twitter 🙂!

Collapse
rouilj profile image
John P. Rouillard

Setting display: none removes the button. So you can't click on it.

Setting opacity keeps the button in place and you can interact with it. You can see this in the last example with the display scrolled to the top. Hover the cursor over the location of the button. Note how the cursor changes to a hand shape.

If you happen to have a link under the button the user can't click on it. If the user happens to click on that location (say to interact with a link or highlight text), it will jump to the top of page.

You have to do more than just set opacity to make this non-confusing for a user. I realize this tutorial is meant for beginners, but these are things that a beginner should have brought to their attention so they don't have to unlearn it in the future. Implementation can be left as an exercise for the reader 8-).

Collapse
ljcdev profile image
ljc-dev Author

Hey John, thx for the precious feedback! I didn't notice that the button was still inside the page 😅. I've increased the translate value from 50 to 100px because it's at 50px from the bottom and its height is 35px so by translating 100px down it's completely out of the screen. Thx again for taking your time to explain this flaw 😁!!!

Collapse
svejdam profile image
Martin Svejda

Very helpful thank you!

Collapse
ljcdev profile image
ljc-dev Author

Thx for the support buddy 😀😊!! I hope I was clear enough. Don't hesitate to tell me if u'd like me to explain sth 👌.

Collapse
madeline_pc profile image
Madeline

I really enjoy your tutorials. They are very well documented and cover all the details. Nice work.

Collapse
ljcdev profile image
ljc-dev Author

Thx a lot Madeline ❤, I still make plenty of mistakes 😇.

Collapse
jamesncox profile image
James Cox

Nice work, ljc! I learned a lot of neat tricks and tips about scroll properties. Thanks for sharing!

Collapse
ljcdev profile image
ljc-dev Author

Much welcome James, thx for reading 😊😊!!