Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/template-ref-null-with-v-if.md
1---2title: Template Refs Become Null When Elements Are Unmounted3impact: MEDIUM4impactDescription: Refs become null when conditionally rendered elements are removed, causing errors if not handled5type: gotcha6tags: [vue3, template-refs, v-if, watchers, conditional-rendering]7---89# Template Refs Become Null When Elements Are Unmounted1011**Impact: MEDIUM** - When using template refs with `v-if`, the ref becomes `null` when the element is unmounted. Watchers and effects that access these refs must handle the null case to avoid runtime errors.1213This is especially tricky with `watchEffect` since it runs automatically and may execute when the ref is null.1415## Task Checklist1617- [ ] Always check for null before accessing ref properties when using v-if18- [ ] In watchers, explicitly handle the null case (element unmounted or not yet mounted)19- [ ] Consider whether v-show is more appropriate if you need persistent ref access20- [ ] Use optional chaining (?.) when accessing ref properties in uncertain contexts2122**Incorrect:**23```vue24<script setup>25import { ref, watchEffect } from 'vue'2627const inputEl = ref(null)28const showInput = ref(true)2930// WRONG: No null check - will error when v-if is false31watchEffect(() => {32inputEl.value.focus() // TypeError when showInput is false33})34</script>3536<template>37<input v-if="showInput" ref="inputEl" />38<button @click="showInput = !showInput">Toggle</button>39</template>40```4142**Correct:**43```vue44<script setup>45import { ref, watchEffect } from 'vue'4647const inputEl = ref(null)48const showInput = ref(true)4950// CORRECT: Handle both mounted and unmounted states51watchEffect(() => {52if (inputEl.value) {53inputEl.value.focus()54} else {55// Element not mounted yet, or unmounted by v-if56console.log('Input element not available')57}58})59</script>6061<template>62<input v-if="showInput" ref="inputEl" />63<button @click="showInput = !showInput">Toggle</button>64</template>65```6667```vue68<script setup>69import { ref, watch } from 'vue'7071const inputEl = ref(null)72const showInput = ref(true)7374// CORRECT: Watch the ref and handle null explicitly75watch(inputEl, (el) => {76if (el) {77el.focus()78}79})80</script>8182<template>83<input v-if="showInput" ref="inputEl" />84</template>85```8687```vue88<script setup>89import { useTemplateRef, watchEffect } from 'vue'9091// Vue 3.5+ approach92const input = useTemplateRef('my-input')9394// CORRECT: Use optional chaining for safe access95watchEffect(() => {96input.value?.focus()97})98</script>99100<template>101<input v-if="showInput" ref="my-input" />102</template>103```104105```vue106<script setup>107import { ref, onMounted } from 'vue'108109const inputEl = ref(null)110const showInput = ref(true)111112// ALTERNATIVE: Use v-show if you need consistent ref access113// v-show keeps element in DOM, just hides it with CSS114</script>115116<template>117<!-- Element always exists in DOM, ref is never null -->118<input v-show="showInput" ref="inputEl" />119</template>120```121122## Reference123- [Vue.js Template Refs](https://vuejs.org/guide/essentials/template-refs.html)124