Template Refs
While Vue's declarative rendering model abstracts away most of the direct DOM operations for you, there may still be cases where you need direct access to the underlying DOM elements. To achieve this, Vue provides the special ref attribute:
<input ref="input">ref is a special attribute, similar to the key attribute discussed in the v-for chapter. It allows us to obtain a direct reference to a specific DOM element or child component instance after it's mounted. This may be useful when you want to, for example, programmatically focus an input on component mount, or initialize a 3rd party library on an element.
Accessing the Refs
NOTE
useTemplateRef is available in Vue 3.5+.
When using the Composition API, you can access template refs via the useTemplateRef() helper:
<script setup>
import { useTemplateRef, onMounted } from 'vue'
// the first argument must match the ref value in the template
const input = useTemplateRef('my-input')
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="my-input" />
</template>The returned ref is a reactive object whose .value points to the underlying DOM element (or component instance).
TypeScript Support
When using TypeScript, Vue's IDE support and vue-tsc will automatically infer the type of input.value based on what element or component the matching ref attribute is used on.
Lifecycle Considerations
Template refs are only populated after the component has been mounted. Before that, their value is null.
For example, accessing input.value in a template expression will yield null on the first render, because the element does not yet exist in the DOM.
If you are trying to watch the changes of a template ref, make sure to account for the case where the ref has null value:
watchEffect(() => {
if (input.value) {
input.value.focus()
} else {
// not mounted yet, or the element was unmounted (e.g. by v-if)
}
})Ref on Component
ref can also be used on a child component. In this case the reference will be that of a component instance:
<script setup>
import { useTemplateRef, onMounted } from 'vue'
import Child from './Child.vue'
const childRef = useTemplateRef('child')
onMounted(() => {
// childRef.value will hold an instance of <Child />
})
</script>
<template>
<Child ref="child" />
</template>If the child component uses the Options API or does not use <script setup>, the ref gives you access to the child component's this. This means the parent gets full access to every property and method of the child. While this can be convenient, it also tightly couples the parent and child. For this reason, component refs should be used sparingly. In most cases, you should try to implement parent / child interactions using the standard props and emit interfaces first.
An exception here is that components using <script setup> are private by default. A parent component cannot access anything on the child instance unless the child explicitly exposes it using defineExpose macro:
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
// Compiler macros, such as defineExpose, don't need to be imported
defineExpose({
a,
b
})
</script>When this is accessed via a template ref, the parent receives an object like: { a: number, b: number } (refs are automatically unwrapped just like on normal instances).
Note that defineExpose must be called before any await operation in <script setup>. Otherwise, properties and methods exposed after the await operation will not be accessible.
Refs inside v-for
NOTE
This requires Vue 3.5 or above.
When ref is used inside v-for, the corresponding template ref should contain an Array value, which will be populated with the elements after mount:
<script setup>
import { ref, useTemplateRef, onMounted } from 'vue'
const list = ref([
/* ... */
])
const itemRefs = useTemplateRef('items')
onMounted(() => console.log(itemRefs.value))
</script>
<template>
<ul>
<li v-for="item in list" ref="items">
{{ item }}
</li>
</ul>
</template>It should be noted that the ref array does not guarantee the same order as the source array.
Function Refs
Instead of a string key, ref can also be bound to a function. This function is called on each component update and gives you full control over how and where the reference is stored. The function receives the element reference as the first argument:
<input :ref="(el) => { /* assign el to a property or ref */ }">A dynamic :ref binding is required to pass a function. When the element is unmounted, the function is called again with null. You can, of course, use a method instead of an inline function.
