Custom Events With defineEmits

Send Messages Up to the Parent

Custom Events With defineEmits

defineEmits declares the events a component can emit so parents can listen with @event handlers — and TypeScript validates the payloads.

4 min read Level 2/5 #vue#emits#events
What you'll learn
  • Declare emits with defineEmits
  • Emit with the returned function
  • Type emits with TypeScript

Data flows down via props; events flow up via emits. defineEmits declares the events a child can fire, the parent listens with @event="handler", and TypeScript validates the payloads.

Declare With Runtime Options

<script setup>
const emit = defineEmits(['saved', 'cancel'])

function onSubmit() {
  emit('saved', { id: 1, name: 'Ada' })
}
</script>

<template>
  <button @click="onSubmit">Save</button>
  <button @click="emit('cancel')">Cancel</button>
</template>

TypeScript Declaration

Pass a type with event names mapped to argument tuples:

<script setup lang="ts">
interface User { id: number; name: string }

const emit = defineEmits<{
  saved: [user: User]
  cancel: []
  remove: [id: number, soft: boolean]
}>()

const user: User = { id: 1, name: 'Ada' }
emit('saved', user)
emit('remove', 1, true)
</script>

The compiler now refuses emit('saved') with no argument or emit('saved', 123).

Listening in the Parent

<template>
  <UserForm
    @saved="onSaved"
    @cancel="show = false"
    @remove="onRemove"
  />
</template>

<script setup lang="ts">
const onSaved = (user: User) => console.log('saved', user)
const onRemove = (id: number, soft: boolean) => console.log(id, soft)
</script>

v-model — A Special Emit

v-model on a custom component is built on emits — it listens for update:modelValue. We cover this with defineModel later in the course.

Lifecycle Hooks →