# Custom Events
This page assumes you've already read the Components Basics. Read that first if you are new to components.
# Event Names
Like components and props, event names provide an automatic case transformation. If you emit an event from the child component in camelCase, you will be able to add a kebab-cased listener in the parent:
this.$emit('myEvent')
<my-component @my-event="doSomething"></my-component>
As with props casing, we recommend using kebab-cased event listeners when you are using in-DOM templates. If you're using string templates, this limitation does not apply.
# Defining Custom Events
Emitted events can be defined on the component via the emits
option.
app.component('custom-form', {
emits: ['inFocus', 'submit']
})
2
3
When a native event (e.g., click
) is defined in the emits
option, the component event will be used instead of a native event listener.
TIP
It is recommended to define all emitted events in order to better document how a component should work.
# Validate Emitted Events
Similar to prop type validation, an emitted event can be validated if it is defined with the Object syntax instead of the array syntax.
To add validation, the event is assigned a function that receives the arguments passed to the $emit
call and returns a boolean to indicate whether the event is valid or not.
app.component('custom-form', {
emits: {
// No validation
click: null,
// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm(email, password) {
this.$emit('submit', { email, password })
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# v-model
arguments
By default, v-model
on a component uses modelValue
as the prop and update:modelValue
as the event. We can modify these names passing an argument to v-model
:
<my-component v-model:title="bookTitle"></my-component>
In this case, child component will expect a title
prop and emits update:title
event to sync:
app.component('my-component', {
props: {
title: String
},
emits: ['update:title'],
template: `
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)">
`
})
2
3
4
5
6
7
8
9
10
11
12
# Multiple v-model
bindings
By leveraging the ability to target a particular prop and event as we learned before with v-model
arguments, we can now create multiple v-model bindings on a single component instance.
Each v-model will sync to a different prop, without the need for extra options in the component:
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
2
3
4
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName'],
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)">
`
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
See the Pen Multiple v-models by Vue (@Vue) on CodePen.
# Handling v-model
modifiers
When we were learning about form input bindings, we saw that v-model
has built-in modifiers - .trim
, .number
and .lazy
. In some cases, however, you might also want to add your own custom modifiers.
Let's create an example custom modifier, capitalize
, that capitalizes the first letter of the string provided by the v-model
binding.
Modifiers added to a component v-model
will be provided to the component via the modelModifiers
prop. In the below example, we have created a component that contains a modelModifiers
prop that defaults to an empty object.
Notice that when the component's created
lifecycle hook triggers, the modelModifiers
prop contains capitalize
and its value is true
- due to it being set on the v-model
binding v-model.capitalize="myText"
.
<my-component v-model.capitalize="myText"></my-component>
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
template: `
<input type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)">
`,
created() {
console.log(this.modelModifiers) // { capitalize: true }
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Now that we have our prop set up, we can check the modelModifiers
object keys and write a handler to change the emitted value. In the code below we will capitalize the string whenever the <input />
element fires an input
event.
<div id="app">
<my-component v-model.capitalize="myText"></my-component>
{{ myText }}
</div>
2
3
4
const app = Vue.createApp({
data() {
return {
myText: ''
}
}
})
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
},
template: `<input
type="text"
:value="modelValue"
@input="emitValue">`
})
app.mount('#app')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
For v-model
bindings with arguments, the generated prop name will be arg + "Modifiers"
:
<my-component v-model:description.capitalize="myText"></my-component>
app.component('my-component', {
props: ['description', 'descriptionModifiers'],
emits: ['update:description'],
template: `
<input type="text"
:value="description"
@input="$emit('update:description', $event.target.value)">
`,
created() {
console.log(this.descriptionModifiers) // { capitalize: true }
}
})
2
3
4
5
6
7
8
9
10
11
12