๐Ÿ“– Vue 3 slots. Advanced level

vue slots

Slots is one of the most used features in vue. We get used to use Default Slots and Named Slots to pass html template in components. But slots also has two great features - Dynamic Slot Names and Scoped Slots. That is all this article is about.

Dynamic Slot Names

Official vue documentation says:

Vue docs
Dynamic directive arguments also work on v-slot, allowing the definition of dynamic slot names:
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- with shorthand -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

I found it not that clear and obvious as it supposed to be. So here is a neat example: Here we have a simple VArticle.vue component that has 3 named slots - title, description, text to render an article in the correct order and applies the default html styles:

VArticle.vue
<template>
  <h1>
    <slot name="title" />
  </h1>
  <h4>
    <slot name="description" />
  </h4>
  <p>
    <slot name="text" />
  </p>
</template>

And in the parent component we wonโ€™t declare VArticle.vue slots explicitly, but create an object with properties representing slots names where the value will be passed and use v-for and Dynamic directive arguments to resolve the slot:

App.vue
<script setup>
import VArticle from "./VArticle.vue";
const article = {
  title: "Vue slots: advanced level",
  description: "This article is about how to use vue slots",
  text: "lorem ipsum dolor...",
};
</script>

<template>
  <VArticle>
    <template v-for="(val, key) of article" :key="key" #[key]>
      {{ val }}
    </template>
  </VArticle>
</template>

Result:

slots result example 1

Check it on The Vue SFC Playground

Scoped Slots

Principe

Scoped slots is the mechanism of passing child components data up to the parent component template that will be rendered in the place of the slot. To do this <slot /> default component may accept attributes just like components accept props:

slots diagram

Scoped Slots example

App.vue
<script setup>
import MyComponent from "./MyComponent.vue";
</script>

<template>
  <MyComponent v-slot="slotProps">
    {{ slotProps.text }} {{ slotProps.count }}
  </MyComponent>
</template>
MyComponent.vue
<script setup>
const greetingMessage = "Hello World!";
</script>

<template>
  <div>
    <slot :text="greetingMessage" :count="1" />
  </div>
</template>

v-slot directive makes the slot attributes available on the template. But usually v-slot used in pair with JS object destructuring like here:

<!-- Using destructuring -->
<template>
  <MyComponent v-slot="{ text, count }">
    {{ text }} {{ count }}
  </MyComponent>
</template>

This is the most basic example of the scoped slots.

Named Scoped Slots example

It may be also used in pair with the Named Slots:

App.vue
<script setup>
import MyComponent from "./MyComponent.vue";
</script>

<template>
  <MyComponent>
    <template #default="{ text, count }">
      <p>default slot: {{ text }} {{ count }}</p>
    </template>
    <template #date="{ date }">
      <p>date slot: {{ date }}</p>
    </template>
    <template #article="{ title, text, views }">
      <h1>{{ title }}</h1>
      <p>{{ text }}</p>
      <span>{{ views }} views</span>
    </template>
  </MyComponent>
</template>
MyComponent.vue
<script setup>
const greetingMessage = "Hello World!";
const dateString = Date.now();
const someObject = { title: "Title", text: "Lorem ipsum...", views: 12 };
</script>

<template>
  <div>
    <slot :text="greetingMessage" :count="1" />
    <slot name="date" :date="dateString" />
    <slot name="article" v-bind="someObject" />
  </div>
</template>
#name
Slots name attribute wonโ€™t be included in the props because it is reserved
name=โ€œdefaultโ€
If you are mixing named slots with the default scoped slot, you need to use an explicit