Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vue: Pass Slots through from Parent to Child Components

Vue: Pass Slots through from Parent to Child Components

The Situation

  • We've got some components A, B and C which provide different slots.
    const A = {
      template: `<div><slot name="a">Default A Content</slot></div>`
    }
    
    const B = {
      template: `<div><slot name="b">Default B Content</slot></div>`
    }
    
    const C = {
      template: `<div><slot name="c">Default C Content</slot></div>`
    }
  • We have a wrapper component W. It receives one of A, B or C as a prop and renders it. W is not aware which slots are provided by either of them.
    Vue.component('W', {
      props: ['child'],
      template: `<component :is="child" />`
    })
  • We want to write a template that uses W but also use the slots offered by the respective wrapped component.

The Problem

Vue won't let us do the following:

<W :child="A">
  <div slot="a">Special A Content</div>
</W>

It just does nothing. Which is very correct, if you think about it: Slot a is expected to be a slot of W, not of the wrapped A.

See this jsFiddle

The Solution

We need to extend our W component's template to pass through any slots it is provided to its wrapped component.

It looks like this:

Vue.component('W', {
  props: ['child'],
  template: `<component :is="child">
  <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
</component>`
})

Now the example will work just fine: jsFiddle

Bonus: Scoped Slots

Scoped slots like the following...

const D = {
  template: `<div><slot name="d" emoji="🎉">Default D Content</slot></div>`
}

...are not handled by the extended template above. They're just ignored.

However, those can be managed in a very similar fashion to regular slots:

<template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" /></template>

Include that alongside the slot passing from above, and our W component will just pass every slot and scoped slot it receives down to its child:

Vue.component('W', {
  props: ['child'],
  template: `<component :is="child">
  <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
  <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" /></template>
</component>`
})

See it in action in this jsFiddle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.