Chapter 98: Vue ‘mounted’ Lifecycle Hook
Mounted
This is the hook that almost every Vue developer reaches for first when they need to do anything that requires the real DOM to exist.
In modern Vue 3 + <script setup> (2026 standard), the equivalent is onMounted() — and this is the hook you will use very often in real projects.
Let me explain it step by step — like I’m sitting next to you showing you exactly when it runs, what is ready, what is not ready, and the most common real-world patterns.
1. Exact position in the lifecycle – Where mounted / onMounted sits
Here is the full Vue 3 lifecycle order (Composition API names first, Options API in brackets):
|
0 1 2 3 4 5 6 7 8 9 10 11 |
onBeforeMount (beforeMount) ── template compiled, about to insert into DOM onMounted (mounted) ── ← this one – DOM is now live & inserted onBeforeUpdate (beforeUpdate) ── data changed, about to re-render onUpdated (updated) ── DOM has been patched onBeforeUnmount (beforeUnmount) ── about to be destroyed onUnmounted (unmounted) ── component is gone |
mounted / onMounted is the first moment when:
- The component has been rendered
- The real DOM nodes are inserted into the document
- Template refs (ref=”…”) are populated
- You can safely use DOM APIs (getBoundingClientRect, focus(), scrollTo(), etc.)
2. What is available / NOT available in onMounted?
This is the key table — memorize when you can and cannot do certain things.
| Feature / Access | Available in onMounted()? | Reason / Explanation |
|---|---|---|
| this / component instance | Yes | Fully populated |
| data() / ref() / reactive() | Yes | Reactive state is ready |
| props | Yes | Props resolved & injected |
| computed | Yes | All computed properties created & cached |
| methods / functions | Yes | All functions available |
| Template compiled & rendered? | Yes | First render has completed |
| Real DOM / $el | Yes | $el is now the root DOM element |
| Template refs (ref=”…”) | Yes | All ref variables are populated (no longer null) |
| DOM APIs (focus, scroll, measure) | Yes | Safe to call .focus(), .getBoundingClientRect(), addEventListener, etc. |
| this.$emit | Yes | Parent is listening (if it was waiting for mount) |
| this.$parent / $root | Yes | Relationships fully established |
Summary sentence to remember forever:
In onMounted / onMounted(), everything is ready — reactive state, props, computed, methods, the full DOM tree, template refs, and DOM APIs. This is the first safe moment to touch the real DOM or initialize anything that needs rendered elements.
3. Real, Practical Examples – When & How You Use onMounted Every Week
Example 1 – Auto-focus input on mount (most common real use-case)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<template> <div> <button @click="showForm = true">Open Login Form</button> <Transition name="fade"> <form v-if="showForm" class="login-form"> <input ref="emailInput" type="email" placeholder="Email" /> <input type="password" placeholder="Password" /> <button type="submit">Login</button> </form> </Transition> </div> </template> <script setup lang="ts"> import { ref, watch, onMounted, nextTick } from 'vue' const showForm = ref(false) const emailInput = ref<HTMLInputElement | null>(null) watch(showForm, async (isOpen) => { if (isOpen) { // Wait for Vue to finish rendering the input await nextTick() // Now it's safe to focus emailInput.value?.focus() } }) // Alternative – auto-focus on first mount (no v-if) onMounted(() => { console.log('Component mounted – DOM is ready') emailInput.value?.focus() // works because input is already in template }) </script> <style scoped> .fade-enter-active, .fade-leave-active { transition: opacity 0.4s ease; } .fade-enter-from, .fade-leave-to { opacity: 0; } .login-form { margin-top: 1.5rem; padding: 1.5rem; background: #f8fafc; border-radius: 8px; } </style> |
→ onMounted (or nextTick after v-if) is the only safe place to call .focus()
Example 2 – Initialize third-party library (Chart.js, Mapbox, Swiper…)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<template> <div> <canvas ref="chartCanvas" width="600" height="400"></canvas> </div> </template> <script setup lang="ts"> import { ref, onMounted, onBeforeUnmount } from 'vue' import Chart from 'chart.js/auto' const chartCanvas = ref<HTMLCanvasElement | null>(null) let chartInstance: Chart | null = null onMounted(() => { if (!chartCanvas.value) return chartInstance = new Chart(chartCanvas.value, { type: 'bar', data: { labels: ['Jan', 'Feb', 'Mar'], datasets: [{ label: 'Sales', data: [12, 19, 3] }] } }) }) onBeforeUnmount(() => { // Very important – destroy chart to prevent memory leaks if (chartInstance) { chartInstance.destroy() chartInstance = null } }) </script> |
→ onMounted → DOM & canvas exist → safe to initialize Chart.js → onBeforeUnmount → cleanup (prevents memory leaks)
Example 3 – Add / remove event listener
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<script setup lang="ts"> import { onMounted, onBeforeUnmount } from 'vue' function handleResize() { console.log('Window resized:', window.innerWidth) } onMounted(() => { window.addEventListener('resize', handleResize) }) onBeforeUnmount(() => { window.removeEventListener('resize', handleResize) }) </script> |
→ Classic cleanup pattern — prevents memory leaks when component unmounts
4. Quick Summary Table – mounted / onMounted in 2026
| Question | Answer / Reality in 2026 |
|---|---|
| When does it run? | After first render & DOM insertion |
| Is data/props/computed available? | Yes |
| Is DOM / $el / refs available? | Yes – first safe moment |
| Is this available? | Yes (Options API) |
| Do modern developers use it? | Very often – init libs, focus, event listeners, fetch that needs DOM |
| Modern replacement | onMounted(() => { … }) |
| Still asked in interviews? | Yes — “When can you safely access refs?” → mounted |
Pro Tips from Real Projects (Hyderabad 2026)
- Most used hook → onMounted for anything DOM-related
- Always cleanup in onBeforeUnmount — timers, listeners, AbortController, ResizeObserver, 3rd-party lib .destroy()
- Use nextTick() inside onMounted if you need to wait for child components to mount
- In SSR / Nuxt → onMounted runs only client-side — safe for browser APIs
- Never mutate state in a way that causes loops in onUpdated — use onMounted for one-time init
- Combine onMounted + watch for “run once on mount, then re-run on data change”
Your mini homework:
- Create the chart / focus / resize listener examples above
- Toggle a v-if wrapper around the chart → see onMounted / onBeforeUnmount fire
- Add onUpdated → count how many times it runs when clicking +1
- Try accessing ref.value in onBeforeMount → see it’s null
Any part confusing? Want full examples for:
- onMounted + third-party lib (Chart.js / Mapbox / Swiper) full setup?
- Cleanup patterns (timers, event listeners, AbortController)?
- onMounted vs onBeforeMount vs top-level code comparison?
- Lifecycle in <KeepAlive> / <Transition> / <Suspense>?
Just tell me — we’ll trace the lifecycle and build real examples together step by step 🚀
