Custom Events
Components are self-contained Vue application instances. This isolation means that events can occur in a child component without the parent's knowledge. Fortunately, Vue has a process for a child component to communicate back up to its parent by using custom events.
Imagine a switch component used to toggle a site's dark mode. When the switch is toggled, the site should switch between light and dark mode.
const app = Vue.createApp({
data: function () {
return {
dark: false
}
}
})
app.component('bs-switch', {
template: `
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="formSwitch">
<label
class="form-check-label"
for="formSwitch">
<slot></slot>
</label>
</div>
`
})
But there is a problem. The data property that controls the mode of the site, dark
, is stored within the root component, and best practice states that a component should never directly edit another component's data. So, only the root component can change the value of the dark
property, and only the switch component knows when the value should be changed.
This problem can be solved by creating a custom event, which the child component will emit and for which the parent component will listen.
Start by adding a standard v-on
directive to the child component to listen for a change on the switch. The action of the directive will be to emit a custom event, toggle-dark
, using the $emit
method.
app.component('bs-switch', {
template: `
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="formSwitch"
@change="$emit('toggle-dark')">
<label
class="form-check-label"
for="formSwitch">
<slot></slot>
</label>
</div>
`
})
The parent component will add its own v-on
directive, but instead of listening for the change
event, it will listen for the custom toggle-dark
event. The action of this directive will be toggling the dark
property value.
<main :class="{'dark': dark}">
<bs-switch
@toggle-dark="dark = !dark">
Dark Mode
</bs-switch>
</main>