// Tutorial //

How To Use Component Slots in Vue.js

Published on February 5, 2017 · Updated on March 3, 2021
Default avatar
By Joshua Bemenderfer
Developer and author at DigitalOcean.
How To Use Component Slots in Vue.js

Introduction

Oftentimes you will need to allow your parent Vue components to embed arbitrary content inside of child components. Vue provides a way to accomplish this with slots.

Note: If you are coming from an Angular background, this is a similar concept to transclusion or content projection.

In this tutorial, you will explore an example Vue project with a parent component and child component that shares content with slots.

Prerequisites

If you would like to follow along with this article, you will need:

This tutorial was verified with Node v15.10.0, npm v7.6.0, and vue v2.6.11.

Using Slots

To allow a parent component to pass DOM elements into a child component, provide a <slot> element inside the child component.

Here is an example of a ChildComponent that contains a <slot>:

ChildComponent.vue
<template>
  <div>
    <p>This is the child component.</p>
    <slot></slot>
  </div>
</template>

Here is an example of a ParentComponent that populates the ChildComponent with content:

ParentComponent.vue
<template>
  <div>
    <p>This is the parent component.</p>
    <ChildComponent>
      <p>This is injected content from the parent component.</p>
      <p>It can still bind to data in the parent's scope: {{myVariable}}</p>
    </ChildComponent>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      myVariable: `Parent Variable`
    }
  }
}
</script>

Viewing the application in a web browser will produce the following result:

Output
<div> <p>This is the parent component.</p> <div> <p>This is the child component.</p> <p>This is injected content from the parent component.</p> <p>It can still bind to data in the parent's scope: Parent Variable</p> <div> </div>

Content and data from the parent component are injected into the child component.

Providing Fallback Content

If the parent component does not inject any content into the child component’s <slot>, the child component will render any elements inside its <slot> tag:

Here is an example of a ChildComponent with fallback content:

ChildComponent.vue
<template>
  <div>
    <p>This is the child component.</p>
    <slot>
      <p>Fallback Content</p>
    </slot>
  </div>
</template>

Here is an example of a ParentComponent that has two ChildComponents - one with slot content and one without:

ParentComponent.vue
<template>
  <div>
    <p>This is the parent component with slot data.</p>
    <ChildComponent>
      <p>Slot Content</p>
    </ChildComponent>
    <p>This is the parent component without slot data.</p>
    <ChildCmponent></ChildComponent>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
}
</script>

Viewing the application in a web browser will produce the following result:

Output
<div> <p>This is the parent component with slot data.</p> <div> <p>This is the child component.</p> <p>Slot Content</p> <div> <p>This is the parent component without slot data.</p> <div> <p>This is the child component.</p> <p>Fallback Content</p> <div> </div>

Fallback content appears when slot content is not provided by the parent component.

Note: If there is no <slot> element in the child component <template>, any content from the parent component will be silently discarded.

This completes a brief introduction into using <slot> and fallbacks.

Using Named Slots

Having one <slot> element to inject content can satisfy some use cases. However, you may have other use cases where you want to utilize multiple <slot> elements. It is possible to achieve this with Vue with named slots.

Named slots are <slot> elements with a name attribute to allow for namespaced content injection:

<slot name="slotName"></slot>

Consider an example component that features named slots for main and aside:

ChildComponent.vue
<template>
  <div>
    <main>
      <slot name="main"></slot>
    </main>
    <aside>
      <slot name="aside"></slot>
    </aside>
    <slot></slot>
  </div>
</template>

The parent component populates the main and aside slots. Content that does not reference a named slot populates the empty slot:

ParentComponent.vue
<template>
  <div>
    <ChildComponent>
      <template v-slot:main>
        <p>Custom Main</p>
      </template>
      <template v-slot:aside>
        <p>Custom Aside</p>
      </template>
      <div>
        <p>Custom Content</p>
      </div>
    </ChildComponent>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
}
</script>

Note: Prior to Vue 2.6.0, you would have used slot attributes. It has since been replaced with the v-slot directive. Vue 3 will deprecate and eventually remove slot attributes.

Viewing the application in a web browser will produce the following result:

Output
<div> <div> <main> <p>Custom Main</p> </main> <aside> <p>Custom Aside</p> </aside> <p>Custom Errata</p> <div> </div>

This completes a brief introduction into using named slots.

Conclusion

In this tutorial, you explored a Vue project with a parent component and child component example that shares content with slots.

If you’d like to learn more about Vue.js, check out our Vue.js topic page for exercises and programming projects.


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!