Being able to pass data around your application is extremely important.

There are 3 main types of communication we care about in Vue:

  1. Parent to Child
  2. Child to Parent
  3. Child to Child

It seems that child to child data sharing is where most of the confusion and frustration lay. Parent to child and child to parent are much easier to figure out.

So how do we do it?

The short answer: you don't pass data from one child component to another child component.

Of course, that's not a very satisfying answer β€”Β or helpful one either.

Let me explain what I mean.

The principles of data flow

The first principle of data flow in Vue is this:

Data flows down, never up.

This is what props are for, and why we can't mutate them. Mutating them would be sending data from the child to the parent, and we have a different mechanism for that.

The second principle of data flow is this:

Events are emitted up.

These two principles allow us to send data down the component hierarchy, as well as back up.

They take care of the first two types of component to component communication: parent to child, and child to parent.

Might we find a third principle that helps us with child to child communication?

Nope.

Passing data between child components

So how do we pass data between two child components, components that are siblings?

What we have to do is to stop treating them as siblings, and break that relationship down into it's parts.

If you have a sibling, they are the child of your parent.

The same goes for components.

To communicate from one component (B) to its sibling component (C), we first communicate with the parent (A), which then communicates to the sibling component (C).

   A
 /   \
B     C

Let's look at an example.

Example

Here we have a Toggle component, which shows or hides a piece of content on the page. We also have a Button component that we want to communicate with the Toggle, to switch it between open and closed:

// Parent
<template>
  <div>
    <Toggle :open="true">
      Show or hide this content!
    </Toggle>

    <Button @click="">
      Toggle the content
    </Button>
  </div>
</template>

To follow this pattern we need to:

  1. Pass data up from the Button to the parent
  2. Pass data down from the parent to the Toggle component

Based on the principles of data flow which we just covered, this means we must:

  1. Emit an event from the Button component
  2. Pass data down as a prop to the Toggle component

This is how we would make that work:

// Parent
<template>
  <div>
    <Toggle :open="isOpen">
      Show or hide this content!
    </Toggle>

    <Button @click="isOpen = !isOpen">
      Toggle the content
    </Button>
  </div>
</template>

By adding the state isOpen to the parent, we can facilitate communication between the two sibling components.

When the Button component is clicked it emits an event that updates the isOpen variable. That variable is then passed down to the Toggle component as a prop.