3 different ways of cross-component communication in Svelte
Tags: svelte, webdev, javascript
Published: 2020-05-14 14:57:27

---
title: 3 different ways of cross-component communication in Svelte
published: true
date: 2020-05-14 00:00:00 UTC
tags: svelte, webdev, javascript
canonical_url: https://codechips.me/svelte-cross-component-communication/
---

> originally published on [codechips.me](https://codechips.me/svelte-cross-component-communication/)

How do you pass data between Svelte components? How do you communicate between children and parents? For example, when you need to trigger some action or change state in the parent from a child component. A typical case is to toggle Svelte component's visibility from itself when the visibility state lives in the parent.

## Problem

In your parent component you have three different child components that you want to toggle visibility for. In every child component there is a "close" button. When it's clicked the component should hide itself. Since the "close" button is within each child component, you as a parent can't really control it. What are your options?

Turns out it's quite easy to do in Svelte. I can think of three different ways. Let's go through them all.

### Demo

Looks like you can't easily embed webm videos. You can see the final result [here](https://codechips.me/svelte-cross-component-communication/).

## Setting up the project

Let's dive straight in. The best way to learn is to actually write the code. That way your brain will have time to process the information because it's faster then your typing. We will start by creating a new project.

```text
$ npx degit codechips/svelte-starter-template cross-component-communication
$ cd cross-component-communication && yarn install
$ yarn start
```

Done? Great! We should have a local server running. Now, create three simple Svelte components in `src/components` folder. Create the folder first.

```html
<!-- One.svelte -->
<div class="component">
  <h2>Component One</h2>
  <img src="https://media.giphy.com/media/1Ju5mGZlWAqek/giphy.gif" alt="happy" />
  <button>close</button>
</div>

<!-- Two.svelte -->
<div class="component">
  <h2>Component Two</h2>
  <img src="https://media.giphy.com/media/lcySndwSDLxC4eOU86/giphy.gif" alt="confused" />
  <button>close</button>
</div>

<!-- Three.svelte -->
<div class="component">
  <h2>Component Three</h2>
  <img src="https://media.giphy.com/media/EdRgVzb2X3iJW/giphy.gif" alt="amazed" />
  <button>close</button>
</div>
```

Nothing fancy yet. We will extend them later. Now, change `App.svelte` to the code below.

```html
<!-- App.svelte -->

<style>
  :global(button) {
    display: block;
    margin-top: 1rem;
  }
  :global(body) {
    font-family: sans-serif;
    font-size: 1.25em;
    background-color: #262626;
    color: #cbd5e0;
  }
  :global(h1){
    margin-bottom: 1em;
    margin-block-end: 0;
  }
  :global(.component) {
    padding: 1rem 2rem;
    background-color: #67ecd4;
    margin: 0 2rem 0 0;
    display: inline-block;
    min-height: 28rem;
    color: #262626;
  }
  .menu {
    display: flex;
    margin-bottom: 1rem;
  }
  .menu button {
    margin-right: 1rem;
  }
  .container {
    display: flex;
  }
</style>

<script>
  // import slide animation for some visual FX
  import { slide } from 'svelte/transition';

  import One from './components/One.svelte';
  import Two from './components/Two.svelte';
  import Three from './components/Three.svelte';

  // define booleans for our component visibility status
  let showOne = false;
  let showTwo = false;
  let showThree = false;

</script>

<h1>Svelte Component Communication Examples</h1>

<div class="menu">
  <!-- show component actions -->
  <button on:click={() => (showOne = !showOne)}>show one</button>
  <button on:click={() => (showTwo = !showTwo)}>show two</button>
  <button on:click={() => (showThree = !showThree)}>show three</button>
</div>

<div class="container">
  {#if showOne}
    <div transition:slide|local>
      <One />
    </div>
  {/if}

  {#if showTwo}
    <div transition:slide|local>
      <Two />
    </div>
  {/if}

  {#if showThree}
    <div transition:slide|local>
      <Three />
    </div>
  {/if}
</div>
```

Nothing fancy yet here either. All our components are hidden by default and you can make then visible by clicking on the show buttons. But how can we hide the children if the visibility state is defined in the parent? All of our children has close buttons, but they have no logic bound to them. Let's fill that part in.

## Option One - Passing Down the Handler

This is the most straight forward option. You encapsulate parent's state in a closure and pass it down to the child component that triggers in when needed. In this case we bind it to the button's `on:click` event. Change `One.svelte` component to the following code.

```html
<script>
  // a noop function that will be overridden
  // by passed-in handler
  export let closeHandler = () => {};
</script>

<div class="component">
  <h2>Component One</h2>
  <img src="https://media.giphy.com/media/1Ju5mGZlWAqek/giphy.gif" alt="happy" />
  <button on:click={closeHandler}>close</button>
</div>
```

What's going on here? We are exposing a `closeHandler` function from the component. This means that we can pass a property `closeHandler` to the component from our parent. We initially assign it to a dummy noop function so it doesn't blow up when we click the button and no handler was passed. Let's add this.

```js
// add this function to the App.svelte
const closeOne = () => (showOne = false);
```

We also need to pass the closure to our `One.component`. Change to this in `App.svelte`.

```html
<!-- we pass in our local handler to the component -->
<One closeHandler={closeOne} />
```

Now it should be possible to close the component from the component itself. First option completed!

## Option Two - Binding State to Local Variable

If you export a variable in the child component you can bind it in the parent by using `bind:var={local}` property where `var` is the variable name in the child component and `local` is the parent's local variable.

```html
<!-- Two.svelte -->

<script>
  // since the variable is exported we can bind
  // to it in our App.svelte
  export let show = false;
</script>

<div class="component">
  <h2>Component Two</h2>
  <img src="https://media.giphy.com/media/lcySndwSDLxC4eOU86/giphy.gif" alt="confused" />
  <button on:click={() => (show = false)}>close</button>
</div>
```

The only thing we need to do in `App.svelte` is to bind it to local variable.

```html
<!-- we bind Two.show variable to our local showTwo variable -->
<Two bind:show={showTwo} />
```

**Tip**: if the variable name is the same both in parent and child then you can use a shortcut `bind:foo` where `foo` is the shared variable name.

It should now be possible to close the component. Second option is now complete!

## Option Three - Dispatching Messages

The last option you have is to use Svelte's [dispatcher](https://svelte.dev/docs#createEventDispatcher) to send messages between components. This is the most flexible option, but also the most complex one of the three. Personally, I don't use it that much as I don't like that you have to destructure the received event. It feels noisy for some reason.

Change the code in our `Three.svelte` component to following.

```html
<!-- Three.svelte -->

<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  // when the handler is triggered in on:click
  // can subscribe to the on:close message in our App.svelte
  // and do what's needed
  const closeHandler = () => dispatch('close');
</script>

<div class="component">
  <h2>Component Three</h2>
  <img src="https://media.giphy.com/media/EdRgVzb2X3iJW/giphy.gif" alt="amazed" />
  <button on:click={closeHandler}>close</button>
</div>
```

We also need to subscribe to the message in `App.svelte`. Change to following.

```html
<!-- Three.svelte -->

<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  // when the handler is triggered in on:click
  // can subscribe to the on:close message in our App.svelte
  // and do what's needed
  const closeHandler = () => dispatch('close');
</script>

<div class="component">
  <h2>Component Three</h2>
  <img src="https://media.giphy.com/media/EdRgVzb2X3iJW/giphy.gif" alt="amazed" />
  <button on:click={closeHandler}>close</button>
</div>
```

What's going on here? We initialize an event dispatcher in our component and then in the `on:click` handler we dispatch a `close` message that parent listens to. Since we only care about the message name we don't need to send any data.

**Note**: dispatcher can only be used in parent/child relationships. Meaning, you cannot use dispatcher to send messages from parent to children. Only the other way around.

You should now be able to close the third component as well. Third option is also done.

## Conclusion

There you go. By now you should know three different ways of how to share data between components. Which one is the best depends on your use case of course. Start simple and adjust to your needs if it doesn't work. If you have more complex needs, where multiple components need to "listen" for data, then Svelte's [stores](https://svelte.dev/docs#svelte_store) might be a better option.

Here is the full example code [https://github.com/codechips/svelte-component-communication](https://github.com/codechips/svelte-component-communication)

---
Follow me on [Twitter](https://twitter.com/codechips) if you want to learn more about Svelte and modern reactive web development in general  😊