How to use Vue Template Refs to Access HTML Elements
📣 Sponsor
Vue gives us a lot of powerful features when it comes to manipulating the DOM. It simplifies the job of maintaining states, to create UIs which are easy to maintain, and fun to use. One thing Vue does really well, is removes the need for direct DOM manipulation. Sometimes, though, we still need to manipulate or reference DOM elements themselves. Fortunately, Vue has thought of this, and allows us to do this with the ref
attribute. We'll cover how you can do this with the Options API, and then with the Composition API.
Referencing DOM Elements in Vue
Although it's certainly possible to use .querySelector()
on a Vue document, it's not best practice. If we want to reference a DOM element, we can use the ref
attribute in Vue.
Let's look at a quick example. Below, we have our App.vue
page, which has an input, and we want to reference that input directly in one of our methods:
<template>
<button id="myButton">Some Button</button>
</template>
<script>
export default {
mounted: function() {
}
}
</script>
Vue can store references to DOM elements in a property called $ref
. The first thing we have to do, is add a ref attribute to the element we want to reference in our Javascript. The value of the ref
attribute will be the name of it within the $ref
property.
For mine, I am calling it myButton
:
<template>
<button id="myButton" ref="myButton"></button>
</template>
Next, in our Javascript, we can call upon that reference, as shown below:
export default {
mounted: function() {
console.log(this.$ref.myButton);
}
This will return the DOM element itself - so you can manipulate it like you'd manipulate any DOM element.
Referencing Child Components
If our button was a component, we could also access it using the same ideas. For example suppose we have a child component, called TestComponent
. We can add a ref
directly to the child component, as shown below:
<template>
<button id="myButton" ref="myButton">Some Button</button>
<TestComponent ref="anotherButton" />
</template>
<script>
import TestComponent from '../components/TestComponent.vue';
export default {
components: {
TestComponent
},
mounted: function() {
// Console logs our "myButton"
console.log(this.$refs.myButton);
// Console logs "anotherButton"
console.log(this.$refs.anotherButton);
}
}
</script>
Above, we add ref
to the component itself:
<TestComponent ref="anotherButton" />
The difference here, is that it doesn't return the DOM element itself - it instead returns an object for the child component.
Referencing a Child Component's DOM element
Since we get an object for a child component when using references, if we want to access the DOM element within a child component itself, we have to use $el
- which will refer to the DOM element in the component itself.
// This is the child component reference
this.$refs.anotherButton
// This is the DOM element for the component
this.$refs.anotherButton.$el
Referencing a Child Component's Method
Since a referencing a child component refers to the entire component, we can reference its methods using this reference. Let's say our child component has Javascript that looks like the code below.
TestComponent.vue
<script>
export default {
methods: {
someFunction: function() {
console.log('Hello');
}
}
}
In our main, App.vue
file, we can reference this method through our reference. For example:
<template>
<button id="myButton" ref="myButton">Some Button</button>
<TestComponent ref="anotherButton" />
</template>
<script>
import TestComponent from '../components/TestComponent.vue';
export default {
components: {
TestComponent
},
mounted: function() {
this.$refs.anotherButton.someFunction();
}
}
</script>
Above, since we have added a reference ref="anotherButton"
to the child component, we can reference it in our Javascript through that reference. All methods are available through this reference:
this.$refs.anotherButton.someFunction();
Composition API - Using Template Refs
Things are a little different if you are using the composition API. In this case, we don't have access to the this.$refs
object. So instead we need to define a variable to hold our ref
. For example, if I wanted to access the input
element below using a ref
with the composition API, I have to do this:
<script setup>
import { ref, onMounted } from 'vue'
const myInput = ref("");
onMounted(() => {
console.log(myInput.value);
})
</script>
<template>
<input ref="myInput">
</template>
Above, we have an input
with the ref myInput
. We define a variable in our setup script called myInput
which holds a ref
function. Now when onMounted
fires and the HTML code has loaded, we can access the DOM element referenced via myInput.ref
.
Using References with v-for
The same concepts apply to v-for
. If you use a ref
on a v-for
element, each element produced by the v-for
loop, will be returned as an array within that reference.
For example, let's say we have the following code:
<template>
<ul>
<li v-for="(item, index) in locations" :key="index" ref="myLocations">{{ item.name }}</li>
</ul>
</template>
<script>
export default {
data() {
return {
locations: [
{ name: 'London', date: '11/02/2022' },
{ name: 'Paris', date: '12/01/2022' },
{ name: 'Tokyo', date: '04/06/2021' }
]
}
},
mounted: function() {
let liElements = this.$refs.myLocations;
console.log(liElements);
}
}
</script>
Since we've added a ref
called myLocations
to our li
element, we can now access it via this.$refs.myLocation
. Since it is also a v-for
, myLocation
will be an array. To get the second li
element, we would do the following:
this.$refs.myLocations[1];
Conclusion
References in Vue are a powerful way to access the DOM elements that Vue produces. They are also the best way to do it when working within the Vue framework. I hope you've enjoyed this article. For more Vue content, you can find it here.
More Tips and Tricks for Vue
- Creating a Reusable Tab Component in Vue
- Getting Started with Storing Vue Data in Vuex
- How to use Templates in Vue
- How v-if and v-else work in Vue
- Navigation between views in Vue with Vue Router
- How to use Vue Template Refs to Access HTML Elements
- Globally Registering Vue Components
- Vue Tips: Dynamic CSS with Vue Reactive Variables
- A Guide to Understanding Vue Lifecycle Hooks
- How to give Props Default Values in Vue