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.