Child components communicate up to parents by emitting custom events using defineEmits().
<!-- SearchBar.vue -->
<script setup>
import { ref } from 'vue'
const emit = defineEmits(['search', 'clear'])
const query = ref('')
function handleSubmit() {
emit('search', query.value)
}
function handleClear() {
query.value = ''
emit('clear')
}
</script>
<template>
<form @submit.prevent="handleSubmit">
<input v-model="query" />
<button type="submit">Search</button>
<button type="button" @click="handleClear">Clear</button>
</form>
</template>
<SearchBar
@search="handleSearch"
@clear="handleClear"
/>
Vue 3 implements v-model on components using modelValue prop + update:modelValue emit:
<!-- BaseInput.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
<!-- Usage -->
<BaseInput v-model="username" />