vue.jscomponentsvue-componentwrapperbootstrap-vue

Vue - how to pass down slots inside wrapper component?


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?


Solution

  • 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.
    <template v-for="(_, slot) of $slots" v-slot:[slot]="scope"><slot :name="slot" v-bind="scope"/></template>
    

    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.