Normally, Vue encourages us to work with reactivity instead of touching the DOM directly. But sometimes you need low-level DOM access (e.g., focusing an input, measuring element size, scrolling to a section).
In the Vue 3.3+ Composition API, we now have a clean utility: useTemplateRef.
What is useTemplateRef?
-
It’s a Composition API helper to easily grab template refs.
-
Think of it as a typed, reactive replacement for the old
ref="myElement"+onMounted()combo. -
It works by binding a template element to a JavaScript variable.
Basic Example: Focusing an Input
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const inputEl = useTemplateRef('inputEl')
onMounted(() => {
// Direct DOM manipulation
inputEl.value?.focus()
})
</script>
<template>
<input type="text" ref="inputEl" placeholder="I’ll be focused on mount" />
</template>
👉 inputEl.value will hold the actual DOM node.
Accessing Other DOM Properties
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const box = useTemplateRef('box')
onMounted(() => {
console.log('Box width:', box.value.offsetWidth)
console.log('Box height:', box.value.offsetHeight)
})
</script>
<template>
<div ref="box" style="width: 200px; height: 100px; background: lightblue;">
Measured box
</div>
</template>
Manipulating Scroll
<script setup>
import { useTemplateRef } from 'vue'
const container = useTemplateRef('container')
function scrollToBottom() {
container.value.scrollTop = container.value.scrollHeight
}
</script>
<template>
<div ref="container" style="height: 150px; overflow-y: auto; border: 1px solid #ccc;">
<p v-for="n in 20" :key="n">Item {{ n }}</p>
</div>
<button @click="scrollToBottom">Scroll to bottom</button>
</template>
Comparing useTemplateRef vs Classic ref
Old way (before Vue 3.3):
<script setup>
import { ref, onMounted } from 'vue'
const inputEl = ref(null)
onMounted(() => {
inputEl.value.focus()
})
</script>
<template>
<input ref="inputEl" />
</template>
New way with useTemplateRef:
What's your reaction?
Excited
0
Happy
0
Not Sure
0
Confused
0


