Vue - how to pass down slots inside wrapper component?

26,397

Solution 1

Vue 3

Same as the Vue 2.6 example below except:

  • $listeners has been merged into $attrs so v-on="$listeners" is no longer necessary. See the migration guide.
  • $scopedSlots is now just $slots. See migration guide.

Vue 2.6 (v-slot syntax)

All ordinary slots will be added to scoped slots, so you only need to do this:

<wrapper>
  <b-table v-bind="$attrs" v-on="$listeners">
    <template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
  </b-table>
</wrapper>

Vue 2.5

See Paul's answer.


Original answer

You need to specify the slots like this:

<wrapper>
  <b-table v-bind="$attrs" v-on="$listeners">
    <!-- Pass on the default slot -->
    <slot/>

    <!-- Pass on any named slots -->
    <slot name="foo" slot="foo"/>
    <slot name="bar" slot="bar"/>

    <!-- Pass on any scoped slots -->
    <template slot="baz" slot-scope="scope"><slot name="baz" v-bind="scope"/></template>
  </b-table>
</wrapper>

Render function

render(h) {
  const children = Object.keys(this.$slots).map(slot => h('template', { slot }, this.$slots[slot]))
  return h('wrapper', [
    h('b-table', {
      attrs: this.$attrs,
      on: this.$listeners,
      scopedSlots: this.$scopedSlots,
    }, children)
  ])
}

You probably also want to set inheritAttrs to false on the component.

Solution 2

I have been automating the passing of any (and all) slots using v-for, as shown below. The nice thing with this method is that you don't need to know which slots have to be passed on, including the default slot. Any slots passed to the wrapper will be passed on.

<wrapper>
  <b-table v-bind="$attrs" v-on="$listeners">

    <!-- Pass on all named slots -->
    <slot v-for="slot in Object.keys($slots)" :name="slot" :slot="slot"/>

    <!-- Pass on all scoped slots -->
    <template v-for="slot in Object.keys($scopedSlots)" :slot="slot" slot-scope="scope"><slot :name="slot" v-bind="scope"/></template>

  </b-table>
</wrapper>

Solution 3

Here is updated syntax for vue >2.6 with scoped slots and regular slots, thanks Nikita-Polyakov, link to discussion

<!-- pass through scoped slots -->
<template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
  <slot :name="scopedSlotName" v-bind="slotData" />
</template>

<!-- pass through normal slots -->
<template v-for="(_, slotName) in $slots" v-slot:[slotName]>
  <slot :name="slotName" />
</template>

<!-- after iterating over slots and scopedSlots, you can customize them like this -->
<template v-slot:overrideExample>
    <slot name="overrideExample" />
    <span>This text content goes to overrideExample slot</span>
</template>
Share:
26,397

Related videos on Youtube

user3599803
Author by

user3599803

Updated on July 08, 2022

Comments

  • user3599803
    user3599803 almost 2 years

    So I've created a simple wrapper component with template like:

    <wrapper>
       <b-table v-bind="$attrs" v-on="$listeners"></b-table>
    </wrapper>
    

    using $attrs and $listeners to pass down props and events.
    Works fine, but how can the wrapper proxy the <b-table> named slots to the child?

  • pouria
    pouria almost 3 years
    The answer for "Vue 2.6" doesn't work for me when using a named slot (on vue 2.6.11). If I remove the parts ="scope" and v-bind="scope", it works for named slots but I can't use it for scoped slots any more :(
  • Excalibaard
    Excalibaard over 2 years
    I'm having the same issue with 2.6. It seems that the issue is with trying to access the scope o non-scoped slots. Sergey's answer below has worked for me.
  • JeppePepp
    JeppePepp almost 2 years
    This line is the magic if you wanna use the scoped slots from parent for vuetify data-tables (you wanna specify the UI for a specific column from parent component wrapping the data-table). <template v-for="slot in Object.keys($scopedSlots)" :slot="slot" slot-scope="scope"><slot :name="slot" v-bind="scope"/></template>