- We've got some components
A
,B
andC
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 ofA
,B
orC
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.
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
.
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
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.
In their essence, scoped slots are just a more powerful superset of "regular" slots. But since introducing them needed a slightly different API, Vue 2 had to distinguish between $slots
and $scopedSlots
.
Vue 3 took the chance and unified both APIs. The less powerful old slots are gone and the old scoped slots are now just called "slots".
Passing on all slots in Vue 3 is similar (but not exactly equivalent) to passing on scoped slots in Vue 2, so here is the W
component from the previous section, adjusted to Vue 3:
Vue.component('W', {
props: ['child'],
template: `<component :is="child">
<template v-for="(_, name) in $slots" v-slot:[name]="slotData"><slot :name="name" v-bind="slotData" /></template>
</component>`
})