Post cover

How to Use nextTick() in Vue

Updated January 30, 2023

A change to Vue component's data (props or state) isn't immediately reflected in the DOM. Rather, Vue updates DOM asynchronously.

You can catch the moment when Vue updates DOM using Vue.nextTick() or vm.$nextTick() functions. Let's see in detail how these functions work.

1. nextTick()

When changing Vue component data the DOM is updated asynchronously. Vue collects multiple updates to virtual DOM from all the components, then creates a single batch to update the DOM.

Updating DOM in a single batch is more performant than doing multiple small updates.

For example, let's consider a component that toggles the display of an element:

vue
<script setup>
import { ref } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = () => {
show.value = !show.value
console.log(show.value, content.value)
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Try the demo.

Clicking on "Insert/Remove" button changes show flag, which toggles the display of <div id="content"> element using v-if="show" directive.

Looking into handleClick, right after data mutation show.value = !show.value, the logged DOM data doesn't correspond to show value. If show is true, then content is null: which means that DOM is not in sync with the component's data.

If you want to catch the moment when DOM has just been updated, then you need to use a special function nextTick(callback). It executes callback right after the new data updates have reached DOM.

Let's find the moment when the <div> element is inserted or removed from the DOM:

vue
<script setup>
import { ref, nextTick } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = () => {
show.value = !show.value
nextTick(() => {
console.log(show.value, content.value)
})
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Try the demo.

Open the demo and click a few times the Insert/Remove button. You'd see that content (the reference that contains the <div> element) is null or contains an element in exact correspondence with show value.

Also, nextTick(callback) executes the callback when all children components updates have been submitted to DOM.

There's also this.$nextTick(callback) available on the component instance, which you might find useful in the case of options API.

2. nextTick() with async/await

If nextTick() is called without arguments, then the function return a promise that resolves when component data changes reach DOM.

That helps leverage the more readable async/await syntax.

For example, let's make the previous component more readable by catching the DOM update with the async/await syntax:

vue
<script setup>
import { ref, nextTick } from 'vue'
const show = ref(true)
const content = ref()
const handleClick = async () => {
show.value = !show.value
await nextTick()
console.log(show.value, content.value)
}
</script>
<template>
<div>
<button @click="handleClick">Insert/Remove</button>
<div v-if="show" ref="content">I am an element</div>
</div>
</template>

Try the demo.

const handleClick = async () => {...} has been marked as an asynchronous function.

When the Insert/Remove button is clicked, the value of show changes.

await nextTick() awaits until the changes reach DOM. Finally, console.log(content) logs the actual content of the reference.

My recommendation is to use the nextTick() with the async/await syntax since it's more readable than the callback approach.

3. Conclusion

When you change the component's data, Vue updates the DOM asynchronously.

If you want to catch the moment when DOM has been updated after the component's data change, then you need to use nextTick(callback) or this.$nextTick(callback) (options API) functions.

Their single callback argument is invoked right after DOM update: and you are guaranteed to get the latest DOM in sync with the component's data.

Alternatively, if you don't supply the callback argument to nextTick(): then the functions would return a promise that's being resolved when DOM is updated.

I recommend using nextTick() with async/await syntax thanks to better readability.

Like the post? Please share!

Quality posts into your inbox

I regularly publish posts containing:

  • Important JavaScript concepts explained in simple words
  • Overview of new JavaScript features
  • How to use TypeScript and typing
  • Software design and good coding practices

Subscribe to my newsletter to get them right into your inbox.

Join 6936 other subscribers.
Dmitri Pavlutin

About Dmitri Pavlutin

Tech writer and coach. My daily routine consists of (but not limited to) drinking coffee, coding, writing, coaching, overcoming boredom 😉.

Quality posts into your inbox

I regularly publish posts containing:

  • Important JavaScript concepts explained in simple words
  • Overview of new JavaScript features
  • How to use TypeScript and typing
  • Software design and good coding practices

Subscribe to my newsletter to get them right into your inbox.

Join 6936 other subscribers.
Dmitri Pavlutin

About Dmitri Pavlutin

Tech writer and coach. My daily routine consists of (but not limited to) drinking coffee, coding, writing, coaching, overcoming boredom 😉.