Simple Vue.js and Tailwind.css Scroll To Top Button

Adam Bailey • January 6, 2022

laravel vue


A simple scroll to top button made with Vue.js and Tailwind.css.


I recently built an app that ended up having some pretty long scrolls, and even just working on the app, I had a constant need to just jump to the top. The top of the page is usually where the navigation lives, and I just want to jump back quickly.

I realize I can just use the command + up arrow on a keyboard, but over half my traffic is mobile, and that's a lot of thumbing for people trying to use these apps.

I used Vue.js and Tailwind.css because I really enjoy working with them. Most of my projects use this front end stack, so it's really easy to just copy these components from project to project and have them "just work".

You may be looking for a solution that does the same, so I thought I'd share how I built my scroll to top button. Let's get started.

Template Code

I'm starting with this button in the vue template:

2 <div
3 ref="scrollTopButton"
4 class="sticky w-full flex justify-end bottom-0 pb-3 pr-5 transition"
5 >
6 <div
7 class="text-gray-400 hover:text-blue-400 transition"
8 >
9 <button>
10 Scroll to top
11 </button>
12 </div>
13 </div>

This adds a button with a ref of scrollTopButton in the bottom right side of the screen and makes it sticky, so it stays there on scroll. Go ahead and take some time to style this how you want it to look for your app.

Add Scroll Listener

Let's add the script and some code for listening to the scroll event.

2 import { defineComponent } from "vue";
4 export default defineComponent({
5 mounted() {
6 window.addEventListener("scroll", this.handleScroll);
7 },
9 beforeUnmount() {
10 window.removeEventListener("scroll", this.handleScroll);
11 },
13 methods: {
14 handleScroll() {
15 const scrollBtn = this.$refs.scrollTopButton;
17 if (window.scrollY > 0) {
18 scrollBtn.classList.remove("invisible");
19 } else {
20 scrollBtn.classList.add("invisible");
21 }
22 },
23 },
24 });

As you can see, we've added and removed an eventListener, with vue's mounted() and beforeUnmount() lifecycle hooks.

Then, we get that button by its ref, and check to see if window.scrollY is more than 0, which means that you are at the top of the page. You may adjust this value if you only want to see the button after you've scrolled down a little.

When your value is reached, we are removing the tailwind class invisible, else we are adding it. Let's also add invisible to this component, so its invisible initially.

2 ref="scrollTopButton"
- class="sticky w-full flex justify-end bottom-0 pb-3 pr-5 lg:pr-16 transition"
+ class="invisible sticky w-full flex justify-end bottom-0 pb-3 pr-5 lg:pr-16 transition"

At this point your button should show if you start to scroll down, and disappear if you're at the top of the page.

Scroll Click Event

Now, we need to make the button actually scroll to the top when you click it!

Add this method to trhe methods section of your script. It smoothly rolls the screen back up to window.scrollY = 0, which would also make your button disappear.

1scrollToTop() {
2 window.scrollTo({ top: 0, behavior: "smooth" });

Let's add the click event to the button itself.

+<button @click="scrollToTop">

And with this, you should have a basic, functional scroll to top button which you should be able to tweak style as needed for your own Vue.js/Tailwind.css project.

Further Improvements

Lodash debounce

If you have Lodash in your project, we could make use of the debounce function to make the button appear after a timeout.

Import debounce:

1import debounce from "lodash/debounce";

Set a data property to hold the method we will call in the listeners:

1data() {
2 return {
3 handleDebouncedScroll: null,
4 };

Apply the debounce method and listener to this data property:

1mounted() {
- window.addEventListener("scroll", this.handleScroll);
+ this.handleDebouncedScroll = debounce(this.handleScroll, 100);
+ window.addEventListener("scroll", this.handleDebouncedScroll);

Remove listener from the debounced method instead:

1beforeUnmount() {
- window.removeEventListener("scroll", this.handleScroll);
+ window.removeEventListener("scroll", this.handleDebouncedScroll);

And now, your button will appear 100 milliseconds after the window.scrollY limit is reached.

Accessible icon button

It is best to have the button display text that helps everyone understand what the purpose of the button is. But, if you are like me and just want an icon in the button, it would be a good idea to make sure assistive technology can still process it.

To add an icon, grab one from your favorite library. I use Remix Icon.

1<button @click="scrollToTop">
- Scroll to top
+ <i class="text-5xl ri-arrow-up-circle-line"></i>

However, we've now removed any text describing this element. Let's fix that with some aria attributes.

1<button @click="scrollToTop"
+ role="button"
+ aria-label="scroll to top of the page"


I hope this article was helpful to anyone googling around looking for a quick solution for scrolling back up the page. I also hope I did a good enough job of breaking it down into pieces to help you understand.

Happy coding!

You might like other posts in