← Home

What is Vue.js nextTick

January 13, 2021

The DOM in Vue JS is updated asynchronously. When you change a value, the change is not immediately rendered in the DOM. Instead, Vue queues up a DOM update and then updates the DOM. Sometimes you have to manipulate the rendered DOM imediatly after Vue renders it.In these cases you would use nextTick.

We will try to illustrate the role of nextTick in the following example.

Let’s say we have a chat box with incoming and sent messages, and for the sake of simplicity, we will ignore the incoming messages. The goal is to scroll the container immediately after adding a new message.

<template>
  <div id="app">
    <div ref="box" class="box">
      <div v-for="(message, key) in messages" :key="key">{{message.body}}</div>
      ...
    </div>
    <button v-on:click="addMessage">Add message</button>
  </div>
</template>

<style>
.box {
  height: 100px;
  width: 300px;
  overflow: scroll;
  border: 1px solid #000
}
</style>

<script>
export default {
  name: "App",
  data: () => {
    return {
      messages: [
        { body: "Message 1" },
        { body: "Message 2" },
        { body: "Message 3" },
        { body: "Message 4" },
        { body: "Message 5" }
      ]
    };
  },
  methods: {
    async addMessage() {

      // Add message
      this.messages.push({ body: `Message ${this.messages.length+1}`})

      // Scroll bottom
      this.$refs.box.scrollTop = this.$refs.box.scrollHeight
    }
  }
};
</script>

Here’s the CodePen:

When you click add messages multiple times, in the first case, the container scrolls down but never reach the bottom.

Now let’s add nextTick and see if it works:

...
async addMessage() {
  
  // Add message
  this.messages.push({ body: `Message ${this.messages.length+1}`})

  // Wait for DOM to update
  await this.$nextTick()
  
  // Scroll bottom
  this.$refs.box.scrollTop = this.$refs.box.scrollHeight
}
...

Now if you click on add message, in the second case you will notice that the container scrolls to the bottom.

We can pass a callback function into nextTick instead of using it as a promise like this:

...
async addMessage() {
  
  // Add message
  this.messages.push({ body: `Message ${this.messages.length+1}`})

  // Wait for DOM to updaten then scroll down
  this.$nextTick(() => {
    this.$refs.box.scrollTop = this.$refs.box.scrollHeight
  })
  
}
...

This is one of the many examples, like this form submit, where you should use nextTick to watch for the DOM change.


Chafik Gharbi Full-stack web and mobile app developer with JavaScript.