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.