Vue.js Template Refs
Template refs give your code direct access to an element on the page. Vue updates the page for you in most situations, so you rarely touch a real element yourself. A few jobs need that direct access: focusing an input box, measuring the size of a card, scrolling a list, or playing a video. A template ref works like a name tag. You attach the tag to an element, and your script uses the tag to find that element.
Picture a hotel front desk. Guests normally ask the desk for what they need. Now and then a guest needs a key to open one specific door. The ref is that key.
Create a Ref with the ref Attribute
Add the ref attribute to any element and give it a name. Vue stores the real element inside this.$refs under that name.
<div id="app">
<input ref="nameInput" placeholder="Your name">
<button @click="focusInput">Focus the box</button>
</div>
<script>
Vue.createApp({
methods: {
focusInput() {
this.$refs.nameInput.focus();
}
}
}).mount("#app");
</script>A click on the button moves the cursor into the input. The method reads this.$refs.nameInput, which holds the real input element, and calls the browser's own focus() method.
Diagram: Ref Lookup
Template:
<input ref="nameInput">
|
v
Vue registers the element
$refs = { nameInput: <input element> }
|
v
Script:
this.$refs.nameInput.focus() --> cursor appears in the boxUse Refs After the Page Mounts
Refs stay empty until Vue builds the elements. Code that runs too early finds nothing and throws an error. The mounted hook runs after the elements exist, so it is the safe place for first-time access.
mounted() {
this.$refs.nameInput.focus();
}Diagram: Timeline
created() --> $refs is empty (elements do not exist yet) mounted() --> $refs is filled (elements exist, safe to use)
Template Refs with the Composition API
Components written with <script setup> have no this. You create a variable with ref(null) and give it the same name as the ref attribute in the template. Vue fills the variable after mounting. Read the element through the .value property.
<template>
<input ref="searchBox" placeholder="Search">
</template>
<script setup>
import { ref, onMounted } from "vue";
const searchBox = ref(null);
onMounted(() => {
searchBox.value.focus();
});
</script>The variable name and the ref string must match exactly. A mismatch leaves the variable at null.
Refs Inside a v-for Loop
A ref placed inside v-for collects every element into an array. The array order may differ from the source list order, so never rely on index positions to match your data.
<template>
<li v-for="item in items" :key="item" ref="rows">{{ item }}</li>
</template>
<script setup>
import { ref, onMounted } from "vue";
const items = ref(["Tea", "Coffee", "Juice"]);
const rows = ref([]);
onMounted(() => {
console.log(rows.value.length); // 3
});
</script>Refs on Child Components
A ref on a component tag returns the component instance instead of a plain element. A component built with <script setup> keeps its inner data private. The child must publish what the parent may use with defineExpose.
<!-- Child.vue -->
<script setup>
function reset() { /* clear the form */ }
defineExpose({ reset });
</script>
<!-- Parent.vue -->
<Child ref="formBox" />
<button @click="formBox.reset()">Clear</button>Diagram: Parent Reaching a Child
Parent Child
ref="formBox" ------------> defineExpose({ reset })
formBox.reset() -----------> reset() runs inside the childWhen to Use Refs
Good Uses
- Focus an input after a modal opens.
- Scroll a chat window to the newest message.
- Measure the width or height of a box.
- Connect a chart or map library that needs a real element.
Uses to Avoid
- Changing text or style through the element. Data binding handles that safely.
- Reading refs inside the template for display. Use data properties for display values.
Direct changes to an element can disappear when Vue redraws that part of the page. Data binding keeps the page and your data in agreement, so choose it first and reach for a ref only when the browser itself must perform an action.
Summary
Template refs connect a script to a real element or child component. The ref attribute names the element, this.$refs or a ref(null) variable holds it, and the mounted stage guarantees it exists. Refs inside v-for produce arrays, and child components share methods only through defineExpose. Use refs for focus, scroll, measurement, and outside libraries.
