How does nextTick() work?
Vue’s reactivity is fast but not immediate. Yes, you usually see changes right away, but Vue actually processes updates in batches. That’s why sometimes your code runs before the DOM has caught up.
Enter Vue’s not-so-secret hero: nextTick().
Simple definition
ThenextTick() function lets you run a callback after Vue has finished its next DOM update cycle. In other words: a shorthand for “let Vue update the DOM, then do this.”import { nextTick, ref } from 'vue'
const show = ref(false)
function toggleModal() {
show.value = !show.value
nextTick(() => {
console.log('The DOM is now updated!')
})
}
When show.value changes, Vue updates the DOM in the next render tick, not immediately. If you try to measure the DOM right after (e.g., getBoundingClientRect()), you’ll read stale values. nextTick() prevents that.
Why does Vue defer DOM updates?
Vue batches reactive changes to avoid redundant renders. For example:count.value++
message.value = 'Hello'
Both changes are applied in a single render pass. If Vue updated the DOM per line, things would slow down. nextTick() gives you a safe point: “after the batch is done.”TL;DR: nextTick() = “See you after render.”
What actually happens?
Internally, Vue uses the Microtask Queue (e.g.,Promise.resolve().then(...)). So a nextTick() callback is scheduled as the next microtask in the event loop.It looks similar to setTimeout(fn, 0), but nextTick() timing is more precise for Vue’s updates.
nextTick(() => console.log('After microtask'))
setTimeout(() => console.log('After macrotask'))
console.log('Immediate log')
// Output:
// Immediate log
// After microtask
// After macrotask
This precision matters: nextTick() runs as soon as Vue finishes its DOM batch.
Real-world scenario
Triggering an animation:<template>
<div ref="box" class="box"></div>
</template>
<script setup>
import { ref, nextTick } from 'vue'
const box = ref(null)
const visible = ref(false)
function animateBox() {
visible.value = true
nextTick(() => {
box.value.classList.add('fade-in')
})
}
</script>
<style>
.box { opacity: 0; transition: opacity .5s; }
.box.fade-in { opacity: 1; }
</style>
If you add the class immediately after toggling visible, the element might not be in the DOM yet. nextTick() waits and the animation starts cleanly.When should you use nextTick()?
| Situation | Why |
|---|---|
| You need DOM measurements | Access the element’s real size/position |
| You will trigger an animation | Add classes after the element is in the DOM |
| You initialize third-party libs (Chart.js, maps) | Init after the canvas/node actually exists |
| You scroll/focus after a dynamic list update | Ensure the target element is rendered first |
await nextTick
In Vue 3, nextTick() returns a promise. You can await it instead of passing a callback:show.value = true
await nextTick()
console.log('DOM updated—safe to measure!')
Great for async/await flows in setup.Things to watch out for
- You don’t need
nextTick()after every change—Vue already batches updates. nextTick()only waits for Vue’s reactive updates. External DOM changes (from non-Vue libs) may need their own waits.await nextTick()is meaningful within Vue’s lifecycle; outside of it, it may do nothing.
Vue lifecycle and nextTick
Often paired withonMounted/onUpdated:onMounted(async () => {
await nextTick()
console.log('Component rendered!')
})
Run measurements or focus right after mount.Conclusion
Vue defers DOM updates to optimize performance—that’s the secret sauce. Sometimes you need to wait for those updates. That’snextTick()’s job.In short:
nextTick()→ “Let Vue finish the DOM, then continue.”- Microtask timing for ultra-precise scheduling
- Perfect for measurements, animations, and third-party inits
Vue’s
nextTick() is a blink-and-you-miss-it optimization—measured in milliseconds, not seconds.