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 <script setup> is the authoring style used throughout; the Options API is shown only as a contrast.

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.