Svelte.js 3 Component Events Tutorial

In this Svelte tutorial we learn how to communicate from a child component up to its parent with component events.

We cover dispatching and listening for events, send data with an event and forwarding events through a component tree.

Lesson Project

If you want to follow along with the examples in this lesson, you’ll need a Svelte app that was cloned with degit or scaffolded with Vite

If you already have an app from previous lessons, you can use that instead.

What are Component Events in Svelte?

In the Component Props lesson we learned that we can communicate from a parent to a child with props. And in the Context API lesson we learned how to make data available through a nested component tree.

Svelte uses Component Events to communicate from a child component up to a parent component.

How to send (dispatch) an event from a child to a parent in Svelte

To send an event from a child component up to its parent, we create an event dispatcher in the child component, then send that event (with or without additional data) with the new dispatcher.

For our example, we’ll use the root App component as the parent and create the following component as the child.

  • /src/components/MainMenu.svelte

The project should look similar to the following.

Example: project
project-folder/
├── src/
|   ├── components/
|   |   └── MainMenu.svelte
|   └── App.svelte

To create an event dispatcher we import the createEventDispatcher function from the ‘svelte’ package, then store an instance of it.

Syntax: create event dispatcher
<script>
  import { createEventDispatcher } from 'svelte'

  const dispatch = createEventDispatcher()
</script>

We can then use dispatch as a function that takes the following 2 arguments.

  • The custom event to send to the parent.
  • [Optional] Any data we need to send with the event.
Syntax: use event dispatcher
dispatch('eventName', additionalData)

As an example, we’ll define a “close” event in MainMenu when the user clicks a button.

Example: src/components/MainMenu.svelte
<script>
  import { createEventDispatcher } from 'svelte'

  const dispatch = createEventDispatcher()
</script>

<!-- send the 'close' event to the parent -->
<button on:click={ () => dispatch('close') }>Close Menu</button>

That’s all we need to send an event.

How to listen for dispatched events on a parent component in Svelte

Svelte doesn’t auto-capture events in a parent component, the parent has to explicitly listen for it.

To listen for an event on the parent, we bind it with the on: directive on the child component’s instance. And as its value we can specify any functionality we want to execute when the event triggers.

Syntax: listen for event
<ChildComponent on:eventName="functionality" />

To demonstrate, we’ll listen for the “close” event in our root App component (parent) on the MainMenu instance. We’ll also define a boolean to show or hide the menu with an if block.

To keep things simple, we’ll use an inline expression to toggle the variable.

Example: src/App.svelte
<script>
  import MainMenu from './components/MainMenu.svelte'

  let showMenu = true
</script>

{#if showMenu}
  <MainMenu on:close={ () => showMenu = false } />
{/if}

If we run the example in the browser, the menu closes when we click the button.

When we click the button, it fires the dispatcher on the child and sends the “close” event to the root App component. The root App component is listening for the event with the on directive and once it receives it, executes the code that sets showMenu to false.

How to send data with an event in Svelte

We mentioned earlier that the dispatcher can accept a second argument. The second argument can contain any data we want to send with the event, like a string or object.

Syntax: send data with event
dispatch('eventName', additionalData)

As an example, let’s send an object with some data with the event from our MainMenu component.

Example: src/components/MainMenu.svelte
<script>
  import { createEventDispatcher } from 'svelte'

  const dispatch = createEventDispatcher()
  const data = {
    name: 'John'
  }
</script>

<!-- send the 'data' object to the parent -->
<button on:click={ () => dispatch('close', data) }>Close Menu</button>

To capture the data in the parent component, we’ll need to use a handler function. That’s because Svelte automatically gives us the Javascript event object as the first argument.

We can then use that event object’s detail property to access the data we sent through the event.

Syntax: event object
function eventHandler(event) {
  // get data with event.detail
}

To demonstrate, let’s move the menu toggler logic in the root App component to a function.

The function will take the event object as its argument and then use the detail property on it to access the name from our object in an alert.

Example: src/App.svelte
<script>
  import MainMenu from './components/MainMenu.svelte'

  let showMenu = true

  function closeMenu(event) {
    showMenu = false
    alert('Hello ' + event.detail.name)
  }
</script>

{#if showMenu}
  <MainMenu on:close={closeMenu} />
{/if}

This time when we click on the button, it will close the menu and fire an alert that shows the data we sent.

How to forward an event through a component tree in Svelte

Sometimes we’ll need to send an event past a parent component to a grandparent.

Svelte allows us to forward the event by simply omitting the event’s value in the parent.

Syntax: forward event
<ChildComponent on:eventName />

As an example, let’s create the following component that will act as the parent between the root App component (now a grandparent) and the MainMenu child component.

  • /src/components/Parent.svelte

The project should look similar to the following.

Example: project
project-folder/
├── src/
|   ├── components/
|   |   ├── Parent.svelte
|   |   └── MainMenu.svelte
|   └── App.svelte

We want Parent to be nested in the root App component and MainMenu to be nested in Parent . The event will be forwarded from MainMenu through Parent , to be handled in the root App component.

So let’s replace MainMenu with Parent in the root App component.

Example: src/App.svelte
<script>
  import Parent from './components/Parent.svelte'

  let showMenu = true

  function closeMenu(event) {
    showMenu = false
    alert('Hello ' + event.detail.name)
  }
</script>

{#if showMenu}
  <Parent on:close={closeMenu} />
{/if}

As mentioned, Parent will import and use MainMenu , forwarding its “close” event.

Example: src/components/Parent.svelte
<script>
  import MainMenu from './MainMenu.svelte'
</script>

<MainMenu on:close />

When we run the example in the browser, everything still works as expected.

tip Event forwarding works for both custom component events and regular DOM events like click .