Tutorial
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:
- Some familiarity with setting up a Vue.js project and using parent and child components will be beneficial.
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>
:
<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:
<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:
<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 ChildComponent
s - one with slot content and one without:
<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
:
<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:
<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.