Template Refs
|
This section documents the current Vue 3.x release line as published at
the official Vue.js documentation, which is the reference these pages are written and
verified against. No specific patch version is pinned. The Composition API with This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since Vue and its ecosystem iterate quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
A template ref is a direct handle to a DOM element or child component instance that the template rendered — for focus management, measuring, driving an animation, or wiring up a non-Vue library. Reach for one only
when props and events cannot express what you need. The reference is
Template Refs and
useTemplateRef().
useTemplateRef
Since 3.5, useTemplateRef('name') returns a ref whose value is the element or component carrying the
matching ref="name" attribute.
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const input = useTemplateRef('search')
onMounted(() => {
input.value.focus()
})
</script>
<template>
<input ref="search">
</template>
The string must match the ref attribute. The attribute may itself be bound (:ref="dynamicName"), and
useTemplateRef handles that.
The classic pattern
Before 3.5 — and still valid — you declare a ref whose variable name equals the ref attribute value:
<script setup>
import { ref, onMounted } from 'vue'
const input = ref(null) // matches ref="input"
onMounted(() => input.value.focus())
</script>
<template>
<input ref="input">
</template>
useTemplateRef is preferred in new code: it separates the variable name from the attribute string and is
easier to type.
Timing
The ref is null until the component mounts and is populated by the time onMounted runs. If the element is
later removed (an enclosing v-if turns false) the ref returns to null. Never read the ref synchronously
during setup — the DOM does not exist yet. To act on the first assignment with a watcher, use
flush: 'post' (see Watchers):
watch(input, (el) => {
if (el) el.focus()
}, { flush: 'post' })
Refs inside v-for
Put ref on an element inside v-for and the ref holds an array of those elements, populated after mount.
The array order is not guaranteed to match the source array.
<script setup>
import { ref, useTemplateRef } from 'vue'
const list = ref([1, 2, 3])
const items = useTemplateRef('items') // array of <li> after mount
</script>
<template>
<ul>
<li v-for="n in list" :key="n" ref="items">{{ n }}</li>
</ul>
</template>
Function refs
Bind :ref to a function instead of a string. Vue calls it on mount with the element and on unmount with
null — handy for storing handles in a Map. See
Function Refs.
<script setup>
import { ref } from 'vue'
const cells = ref(new Map())
</script>
<template>
<div
v-for="row in rows"
:key="row.id"
:ref="(el) => { if (el) cells.set(row.id, el) }" />
</template>
An inline arrow is a new function on every render, so the ref detaches and re-attaches each update; use a stable method reference if that matters.
Refs on a component
A ref on a child gives you the child’s instance. A <script setup> child is closed by default — the
parent sees nothing unless the child calls defineExpose(). See
Ref on Component.
<!-- Child.vue -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
function reset() { count.value = 0 }
defineExpose({ count, reset })
</script>
<!-- Parent.vue -->
<script setup>
import { useTemplateRef, onMounted } from 'vue'
import Child from './Child.vue'
const child = useTemplateRef('child')
onMounted(() => {
child.value.reset()
console.log(child.value.count) // exposed refs are unwrapped
})
</script>
<template>
<Child ref="child" />
</template>
Components authored with the Options API or a plain setup() return are exposed by default;
<script setup> components are not.
A ref, or props and events?
A template ref is imperative and couples the parent to the child’s internals. Prefer the declarative interface first:
-
Data going in → props.
-
Data or notifications coming out → emitted events (Component Events and v-model).
-
Two-way on a form-like child →
v-model/defineModel().
Keep refs for genuinely imperative actions with no state to model: focus, scroll, play and pause, measuring text, kicking off an animation, or handing an element to a charting library.
See also
-
Lifecycle Hooks —
onMounted, where refs first become available. -
Components Basics — props and events, the declarative alternative.
-
Watchers —
flush: 'post'for watchers that read refs.