Suppose there is a BaseInput.vue component that contains an input element:
<!-- BaseInput.vue -->
<template>
<input type="text">
</template>
The BaseInput.vue component is used inside App.vue:
<!-- App.vue -->
<script setup>
import BaseInput from './components/BaseInput.vue';
</script>
<template>
<BaseInput />
</template>
In App.vue, we can't directly access the input element inside the BaseInput component using ref, it only provides access to the component instance properties.
For example, if we try to focus the input, it will cause an error:
<!-- App.vue -->
<script setup>
import { ref, onMounted } from 'vue'
import BaseInput from './components/BaseInput.vue';
const baseInputEl = ref()
onMounted(() => {
baseInputEl.value.focus() // Uncaught TypeError: baseInputEl.value.focus is not a function
})
</script>
<template>
<BaseInput ref="baseInputEl" />
</template>
To fix this, we can expose the input element inside the BaseInput component using the defineExpose function.
<!-- BaseInput.vue -->
<script setup>
import { ref } from 'vue';
const inputEl = ref()
defineExpose({
inputEl
})
</script>
<template>
<input type="text" ref="inputEl">
</template>
Now, when we access the ref of the BaseInput component, it includes an inputEl property that references the input element inside the component. We can now call focus() on it.
<!-- App.vue -->
<script setup>
import { ref, onMounted } from 'vue'
import BaseInput from './components/BaseInput.vue';
const baseInputEl = ref()
onMounted(() => {
baseInputEl.value.inputEl.focus() // works
})
</script>
<template>
<BaseInput ref="baseInputEl" />
</template>
Additionally, in Vue 3.5, we can use the useTemplateRef function to make it easier to access elements in the template without needing to create a reactive variable with the same name as the ref attribute.
<!-- App.vue -->
<script setup>
import { onMounted, useTemplateRef } from 'vue'
import BaseInput from './components/BaseInput.vue';
const baseInputEl = useTemplateRef('base-input')
onMounted(() => {
baseInputEl.value.inputEl.focus() // works
})
</script>
<template>
<BaseInput ref="base-input" />
</template>
Top comments (2)
Nice, didn't know about defineExpose.
Yeah, it’s really useful in Vue 3.