Skip to content

Instantly share code, notes, and snippets.

@loilo
Last active July 4, 2025 09:46
Show Gist options
  • Save loilo/73c55ed04917ecf5d682ec70a2a1b8e2 to your computer and use it in GitHub Desktop.
Save loilo/73c55ed04917ecf5d682ec70a2a1b8e2 to your computer and use it in GitHub Desktop.

Revisions

  1. loilo revised this gist Nov 18, 2020. 1 changed file with 19 additions and 4 deletions.
    23 changes: 19 additions & 4 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,5 @@
    # Vue: Pass Slots through from Parent to Child Components

    > **Note:** The code below is for Vue 2. I haven't figured out a proper solution for Vue 3 yet, but if I do, I'll update this gist accordingly.
    ## The Situation
    * We've got some components `A`, `B` and `C` which provide different slots.
    ```javascript
    @@ -56,7 +54,7 @@ Vue.component('W', {

    Now the example will work just fine: [jsFiddle](http://jsfiddle.net/Loilo/rzxL4tm2/3/)

    ## Bonus: Scoped Slots
    ## Bonus A: Scoped Slots
    Scoped slots like the following...

    ```javascript
    @@ -85,4 +83,21 @@ Vue.component('W', {
    })
    ```

    See it in action in [this jsFiddle](https://jsfiddle.net/Loilo/7hycewrs/3/).
    See it in action in [this jsFiddle](https://jsfiddle.net/Loilo/7hycewrs/3/).

    ## Bonus B: Vue 3

    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:

    ```javascript
    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>`
    })
    ```
  2. loilo revised this gist Nov 17, 2020. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    # Vue: Pass Slots through from Parent to Child Components

    > **Note:** The code below is for Vue 2. I haven't figured out a proper solution for Vue 3 yet, but if I do, I'll update this gist accordingly.
    ## The Situation
    * We've got some components `A`, `B` and `C` which provide different slots.
    ```javascript
  3. loilo revised this gist Apr 1, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -68,7 +68,7 @@ const D = {
    However, those can be managed in a very similar fashion to regular slots:

    ```vue
    <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" />
    <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:
    @@ -78,7 +78,7 @@ 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 v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" /></template>
    </component>`
    })
    ```
  4. loilo revised this gist Apr 1, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -68,7 +68,7 @@ const D = {
    However, those can be managed in a very similar fashion to regular slots:

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

    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:
    @@ -78,7 +78,7 @@ 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>
    <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData"><slot :name="name" v-bind="slotData" />
    </component>`
    })
    ```
  5. loilo revised this gist Apr 1, 2019. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,7 @@
    ```javascript
    Vue.component('W', {
    props: ['child'],
    template: `<div :is="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.
    @@ -46,9 +46,9 @@ It looks like this:
    ```javascript
    Vue.component('W', {
    props: ['child'],
    template: `<div :is="child">
    template: `<component :is="child">
    <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
    </div>`
    </component>`
    })
    ```

    @@ -76,10 +76,10 @@ Include that alongside the slot passing from above, and our `W` component will j
    ```javascript
    Vue.component('W', {
    props: ['child'],
    template: `<div :is="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>
    </div>`
    </component>`
    })
    ```

  6. loilo revised this gist Sep 13, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    # Vue: Pass Slots through from Parent to Child Components

    ## The Situation
    * We've got some components `A`, `B` and `C` which provides different slots.
    * We've got some components `A`, `B` and `C` which provide different slots.
    ```javascript
    const A = {
    template: `<div><slot name="a">Default A Content</slot></div>`
  7. loilo revised this gist Aug 3, 2018. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,7 @@ Vue won't let us do the following:

    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](http://jsfiddle.net/Loilo/4r836smt/)
    [See this jsFiddle](http://jsfiddle.net/Loilo/4r836smt/1/)

    ## The Solution
    We need to extend our `W` component's template to pass through any slots it is provided to its wrapped component.
    @@ -52,7 +52,7 @@ Vue.component('W', {
    })
    ```

    Now the example will work just fine: [jsFiddle](http://jsfiddle.net/Loilo/rzxL4tm2/1/)
    Now the example will work just fine: [jsFiddle](http://jsfiddle.net/Loilo/rzxL4tm2/3/)

    ## Bonus: Scoped Slots
    Scoped slots like the following...
    @@ -83,4 +83,4 @@ Vue.component('W', {
    })
    ```

    See it in action in [this jsFiddle](https://jsfiddle.net/Loilo/7hycewrs/2/).
    See it in action in [this jsFiddle](https://jsfiddle.net/Loilo/7hycewrs/3/).
  8. loilo created this gist Aug 3, 2018.
    86 changes: 86 additions & 0 deletions pass-slots.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    # Vue: Pass Slots through from Parent to Child Components

    ## The Situation
    * We've got some components `A`, `B` and `C` which provides different slots.
    ```javascript
    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.
    ```javascript
    Vue.component('W', {
    props: ['child'],
    template: `<div :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:

    ```vue
    <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](http://jsfiddle.net/Loilo/4r836smt/)

    ## 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:

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

    Now the example will work just fine: [jsFiddle](http://jsfiddle.net/Loilo/rzxL4tm2/1/)

    ## Bonus: Scoped Slots
    Scoped slots like the following...

    ```javascript
    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:

    ```vue
    <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:

    ```javascript
    Vue.component('W', {
    props: ['child'],
    template: `<div :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>
    </div>`
    })
    ```

    See it in action in [this jsFiddle](https://jsfiddle.net/Loilo/7hycewrs/2/).