Pass all props to children in Vue

jwkicklighter

Jordan Kicklighter

Posted on August 16, 2019

Pass all props to children in Vue

This article is also posted on my blog.

While brainstorming some new Vue components, I wanted to have a way that a single wrapper component could fetch all of the data needed for the children views, and pass that data through (around 5 layers of) children down to the the bottom.

So I did some experimenting, and hereโ€™s a way to pass all component props down through child components. Link to codepen.

Vue actually makes this very easy for us. All component props are available in the $props object (this.$props if you're not in the template), and we can use the Vue directive v-bind without specifying a specific prop name in order to bind a whole object of props to the child.

Example

Let's assume we have some wrapper component that is going to render a child comp1 component and pass it both propForComp1 and propForComp2 as props.

Here's Comp1.vue:

<template>
  <div class="comp1">
    <span>{{ propForComp1 }}</span>
    <comp2 v-bind="$props" />
  </div>
</template>

<script>
  export default {
    components: Comp2,
    props: [
      'propForComp1',
      'propForComp2'
    ],
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Notice that comp1 is only using propForComp1 and doesn't really care about propForComp2. But since it needs to be included in the props passed to comp2, propForComp2 still needs to be declared inside the props object. If not, $props will not contain it.

You can do this for many levels of components, but remember that the props any child needs must be declared in all parents. So if you have 5 layers, propForComp5 must be declared as a prop in prop1, prop2, prop3, prop4, and prop5. You can make this a little easier by using a Mixin, which is the route I took in the codepen.

UPDATE: You actually don't have to do this last bit! Just like Vue gives up $props, the $attrs object includes all of the passed attributes that the component doesn't declare as props. This means, that we can simply use v-bind="$attrs" to pass down the attributes that children would care about, even if the component doesn't specify them itself.

The previous example would turn into:

<template>
  <div class="comp1">
    <span>{{ propForComp1 }}</span>
    <comp2 v-bind="$props" v-bind="$attrs" />
  </div>
</template>

<script>
  export default {
    components: Comp2,
    props: [
      'propForComp1'
    ],
  }
</script>
Enter fullscreen mode Exit fullscreen mode

A diff to see the changes:

<template>
  <div class="comp1">
    <span>{{ propForComp1 }}</span>
-   <comp2 v-bind="$props" />
+   <comp2 v-bind="$props" v-bind="$attrs" />
  </div>
</template>

<script>
  export default {
    components: Comp2,
    props: [
      'propForComp1',
-     'propForComp2'
    ],
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Thanks to @morficus for pointing this out!

๐Ÿ’– ๐Ÿ’ช ๐Ÿ™… ๐Ÿšฉ
jwkicklighter
Jordan Kicklighter

Posted on August 16, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

ยฉ TheLazy.dev

About