What and why?

In Vue, to pass value from parant to a child componnent, we can use props, which can be any type of JavaScript value. In some cases, we want to pass a template, which can have custom styles or combination of multiple html elements. That’s where Slots are useful.

For example, we may have a <FancyButton> component that supports usage like this:

<FancyButton>
  Click me! <!-- slot content -->
</FancyButton>

The template of looks like this:

<button class="fancy-btn">
  <slot></slot> <!-- slot outlet -->
</button>

image

And the final rendered DOM:

<button class="fancy-btn">Click me!</button>

By using slots, our is more flexible and reusable. We can now use it in different places with different inner content, but all with the same fancy styling.

Demo

Render Scope

By default, slot content has access to the data scope of the parent component, because it is defined in the parent. For example:

<span></span>
<FancyButton></FancyButton>

Here both `` interpolations will render the same content.

Fallback Content

It’s the default content for a slot, to be rendered only when no content is provided.

Demo

Named Slots

Allow a single component has multiple slots.

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

Demo

Scoped Slots

Allow the child component pass data to the parent component.

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

Use slotProps:

<MyComponent v-slot="slotProps">
   
</MyComponent>

Use destructuring:

<MyComponent v-slot="{ text, count }">
   8
</MyComponent>

Demo

Dynamic Slot Names

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

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

More Example