Check if a user has scrolled to the bottom in Vue.js

in Code Write a comment

This snippet will be useful for those trying to implement an infinite scroll in Vue.js or load next article when user reaches the bottom of the page.

I came up with a working solution and I wanted to share it with you.

How to find when the user is at the bottom of the page

To achieve that create a new function called scroll and place it within the methods block. This function will calculate if the page offset is equal to the page height. Here is an example:

scroll () {
  window.onscroll = () => {
    let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight === document.documentElement.offsetHeight

    if (bottomOfWindow) {
     this.scrolledToBottom = true // replace it with your code
    }
 }
}

Call this function in the mounted() function.

mounted () {
  this.scroll()
}

Now you’ll know when the user scrolls to the bottom. You may want to declare a scrolledToBottom boolean in the data object and use it in your template. Or you can create a function that will load the next page and place it within the scroll function.

Full example (added on 24 of March 2019):

Vue.js

new Vue({
  el: "#app",
  data: {
    scrolledToBottom: false
  },
  methods: {
    scroll () {
      window.onscroll = () => {
        let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight === document.documentElement.offsetHeight

        if (bottomOfWindow) {
         this.scrolledToBottom = true // replace it with your code
        }
      }
    }
  },
  mounted () {
  	this.scroll()
  }
})

HTML

<div id="app">
  <div class="sticky">
    Scrolled to bottom: {{ scrolledToBottom }}
  </div>
</div>

CSS

body {
  background: #20262E;
  padding: 20px;
}

#app {
  background: #fff;
  height: 200vh;
}

.sticky {
  position: sticky;
  top: 0;
}

https://jsfiddle.net/fgczx4w8/

UPDATE: 20 May 2019

Some users reported that the example above is only working in Chrome. After a quick investigation, I’ve found a bug in the CSS element “position: sticky”. It’s not working properly in Safari and Firefox. Sorry about that. Here’s an updated example, which works in other browsers.


Hi, I'm Renat 👋

 


UPDATE: 2021

If you’re experiencing problems, you can check another solution here.

If you find it useful, please let me know in the comments below.

Make sure you also check how to do Vue.js polling using setInterval() and know the difference between LocalStorage vs SessionStorage vs Cookies.

Incoming search terms:

A collection of UI components for
Bootstrap 4/5 and Vue.js

Get now

Write a Comment

Comment

44 Comments

  1. Hey Renat I tried this solution but it only checks if the page has been scrolled to the top and not the bottom. It seems to be inverse.

    • Hey Desmond! What browser are you using? I’ve added a full example and a link to JSFiddle. Let me know if it works for you.

      • Hi Renat
        I was having the same problem as Desmond, with Chrome and Firefox.
        Removing “margin: none” from the html element sorted with Firefox, but Chrome doesn’t do anything now.
        I using Vue, if that helpd

      • Renat
        Regarding my previous comment, I’ve reapplied the margin and Firefox is still working, absolutely fine to be honest. Also meant to say use a Vue for “___ in___”. Chrome still not playing

          • Hi Renat
            Sorry about the delay in getting back. The position sticky didn’t work on the same computer (Linux Manjaro), but on a different computer (OS Linux Mint) it worked with or without it.
            Not sure if it’s a browser issue, I’m having a problem updating on Manjaro. However, thinking of replacing it with Mint.
            Before I do: If you’ve any suggestions that may help others, I’m willing to give it a try

          • Me again
            Damn, just noticed you said replace sticky with fixed. That screws it up on the computer it was working on

          • Hi David
            What happens when you replace sticky with fixed on the computer it was working on? This could be a caching issue. If you open a JSFiddle example (https://jsfiddle.net/renatello/5xuwfrts/6/) in the incognito mode and tell me if it’s working there that’d be awesome. Also, screenshots will help us debug it.

            I haven’t tested it on any Linux distros but I know that “position: fixed” is supported by all browsers, starting from IE6. Although JSFiddle itself may not be working on some distros other users should be able to copy and paste the code above and replace position sticky with sticky.

  2. Well done mate!
    I did similar stuff in Jquery but unfortunately had no idea how to make this in Vue.
    I was looking for this solution for many hours, of course there are so many plugins for this, but most of them work in strange way…
    It is what I have been looking for.
    Thank you so much.

    • You are very welcome!
      I agree that it’s better to write a custom code rather than use an npm package. I’m glad it worked for you.

  3. Hey, thanks for the article, I have a slight problem, If I enter some action when the user reaches the end of the window the action happens which is great. However, it doesn’t happen when reaching the end but when scrolling from bottom to top.
    Do you know how to fix this?!

  4. Hey so, I want to add an element and scroll down in a div element with overflow: auto. I also want it so if the user scrolls up and a new element is added, it shouldn’t scroll down. Help is appreciated.

    • Hey Saawal! Could you please share your code in some playground like JSFiddle? I should be able to help you then.

  5. it’s working in reverse for me instead of page scroll to bottom it’s working on page scroll to top. am using it without the css style tell me how it will work without the css and am using it in vuejs with chrome browser. thank you

    • Hi Shami, replace this line:

      // if (bottomOfWindow) {

      with these two lines (also add a #bottom-marker to your html part):

      let bottomMarker = document.querySelector('#bottom-marker')
      if (bottomMarker && this.isScrolledIntoView(bottomMarker)) {

      and add this method:

      isScrolledIntoView (el) {
        let rect = el.getBoundingClientRect()
        let elemTop = rect.top
        let elemBottom = rect.bottom
      
        let isVisible = elemTop < window.innerHeight && elemBottom >= 0
        return isVisible
      },
  6. Well Firstly i want to thank you for your sharing.
    i have used this code in one page but its working on the others page.
    I mean i just want to use that in my home page not in the description page.
    What should i do now?
    I am using this in nuxt application.
    Thank you

    • Hi Tanzil! You’re welcome!

      You can either check if the route name is equal to ‘homepage’ or place this code inside your homepage component.

      Let me know if it works!

      • Thanks Man!It Works.I just make a condition if the route path is equal to my home page then data will be added.
        but I do not understand why this happen?
        i place this code in my home page and call the function in the home page mounted life-cycle hook.even i call the function in destroyed hook also.
        Can you have any explanation?
        Thanks Again

  7. Thanks for the explanation. I’ve been searching for hours on a version for a div element. It’s a v-list within a v-dialog (Vuetify).

    I don’t know if it cannot trigger the scroll event on v-for elements or if is there any other issue with nested components.

    I have exactly the same issue that’s described here https://stackoverflow.com/questions/59603315/how-to-detect-when-a-user-scrolls-to-the-bottom-of-a-div-vue

    But there is no answer at the moment…