Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In Vue 3, declare a child component’s events with defineEmits and call the returned function to emit an event and its payload. For Vue 3.3 and later, named-tuple type syntax offers concise compile-time checking; use runtime object declarations when you also need payload validation. For component v-model, use defineModel() in Vue 3.4 and later, or emit update:modelValue directly in earlier versions.

Emit a typed event from a Vue 3 child component

In a component using <script setup lang="ts">, declare events at the top level with defineEmits. Then call the returned emit function with the event name and any payload arguments:

<script setup lang="ts">
const emit = defineEmits<{
  change: [id: number]
  update: [value: string]
}>()

function choose(id: number) {
  emit('change', id)
}
</script>

The declaration describes the event contract: change requires a number, while update requires a string. TypeScript and editor tooling can use that contract to flag misspelled event names or payloads of the wrong type. Vue documents component events and the defineEmits macro.

A parent listens in the template and receives emitted arguments after the event name:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<Child @change="onChange" />

Vue supports automatic case transformation between camelCase event names and kebab-case listeners. Keep the event name consistent with the child’s declaration; kebab-case is the usual template form.

Choose a declaration style for the event contract

Vue supports runtime declarations and TypeScript-only declarations. Use one form per defineEmits call; combining the two forms is a compile error.

Declaration Payload checking Runtime validation Best fit
defineEmits(['change', 'update']) Names are declared, but payload shapes are not expressed. No payload validator. Simple event names when payload type precision is not needed.
defineEmits({ submit(payload) { ... } }) Can describe arguments through TypeScript inference, but a validator is not a substitute for a precise type declaration. Yes. The validator receives emitted arguments and returns a boolean. Cases where a runtime check is useful in addition to the component contract.
Call signatures, such as defineEmits<{ (e: 'change', id: number): void }>() Yes, with explicit event and argument types. No runtime payload validator. Type-based declarations, including Vue versions before named-tuple syntax.
Named tuples, such as defineEmits<{ change: [id: number] }>() Yes, with concise event-specific argument types. No runtime payload validator. Vue 3.3 and later when using TypeScript.

For example, a runtime object validator can reject a malformed payload by returning false:

const emit = defineEmits({
  submit(payload: { email: string; password: string }) {
    return payload.email.length > 0 && payload.password.length > 0
  }
})

Vue’s documentation covers runtime and type-based event declarations and the macro’s type syntax. Type declarations provide compile-time checking and completion; object syntax adds runtime validation where the validator is defined.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use defineEmits correctly in script setup

defineEmits is a compiler macro: do not import it, and place it directly in the top level of <script setup>, not inside a function. Vue states: “The defineEmits() macro cannot be used inside a function, it must be placed directly within <script setup>.” See the official macro documentation.

Declare all events the component can emit. The declaration documents the public contract and tells Vue which listeners belong to the component. Vue can exclude listeners for declared events from $attrs fallthrough to the root element. If you declare a native event name such as click, a parent’s listener handles the component-emitted event rather than acting as an implicit native click listener on the component root. See Vue’s event declaration guidance.

Declare events in an Options API component

For Options API components, put the event declaration in the component’s emits option. Wrapping the component with defineComponent enables TypeScript to check calls to this.$emit, including event names and payloads:

import { defineComponent } from 'vue'

export default defineComponent({
  emits: {
    addBook(payload: { bookName: string }) {
      return payload.bookName.length > 0
    }
  },
  methods: {
    submit() {
      this.$emit('addBook', { bookName: 'Vue Guide' })
    }
  }
})

The object form provides a runtime validator; an Options API component can also declare emitted event names using the emits option. Consult Vue’s TypeScript and Options API guide for typed component patterns.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Emit update:modelValue for component v-model

In Vue 3.4 and later, defineModel() is the recommended convenience macro for component v-model. It represents the model prop and the corresponding update event; changing the model emits update:modelValue under the hood. See Vue’s component v-model guide.

Before Vue 3.4, implement the same default model contract by declaring the modelValue prop and emitting update:modelValue with the new value:

<script setup lang="ts">
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ 'update:modelValue': [value: string] }>()

function updateValue(value: string) {
  emit('update:modelValue', value)
}
</script>

<template>
  <input :value="props.modelValue" @input="updateValue(($event.target as HTMLInputElement).value)" />
</template>

The parent can then use the component with v-model; Vue connects the model prop and update event as the component’s binding contract.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.