URL: https://www.progressiverobot.com/vuejs-component-slots/

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

component illustration for: 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>:

				
					
[label ChildComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;p&gt;This is the child component.&lt;/p&gt;

 &lt;^&gt;&lt;slot&gt;&lt;/slot&gt;&lt;^&gt;

 &lt;/div&gt;

&lt;/template&gt;

				
			

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

				
					
[label ParentComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;p&gt;This is the parent component.&lt;/p&gt;

 &lt;^&gt;&lt;ChildComponent&gt;&lt;^&gt;

 &lt;^&gt;&lt;p&gt;This is injected content from the parent component.&lt;/p&gt;&lt;^&gt;

 &lt;^&gt;&lt;p&gt;It can still bind to data in the parent's scope: {{myVariable}}&lt;/p&gt;&lt;^&gt;

 &lt;^&gt;&lt;/ChildComponent&gt;&lt;^&gt;

 &lt;/div&gt;

&lt;/template&gt;



&lt;script&gt;

&lt;^&gt;import ChildComponent from './ChildComponent.vue';&lt;^&gt;



export default {

 components: {

 &lt;^&gt;ChildComponent&lt;^&gt;

 },

 data() {

 return {

 &lt;^&gt;myVariable: `Parent Variable`&lt;^&gt;

 }

 }

}

&lt;/script&gt;

				
			

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

				
					
[secondary_label Output]

&lt;div&gt;

 &lt;p&gt;This is the parent component.&lt;/p&gt;

 &lt;div&gt;

 &lt;p&gt;This is the child component.&lt;/p&gt;

 &lt;p&gt;This is injected content from the parent component.&lt;/p&gt;

 &lt;p&gt;It can still bind to data in the parent's scope: Parent Variable&lt;/p&gt;

 &lt;div&gt;

&lt;/div&gt;

				
			

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:

				
					
[label ChildComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;p&gt;This is the child component.&lt;/p&gt;

 &lt;slot&gt;

 &lt;p&gt;Fallback Content&lt;/p&gt;

 &lt;/slot&gt;

 &lt;/div&gt;

&lt;/template&gt;

				
			

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

				
					
[label ParentComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;p&gt;This is the parent component with slot data.&lt;/p&gt;

 &lt;ChildComponent&gt;

 &lt;p&gt;Slot Content&lt;/p&gt;

 &lt;/ChildComponent&gt;

 &lt;p&gt;This is the parent component without slot data.&lt;/p&gt;

 &lt;ChildCmponent&gt;&lt;/ChildComponent&gt;

 &lt;/div&gt;

&lt;/template&gt;



&lt;script&gt;

import ChildComponent from './ChildComponent.vue';



export default {

 components: {

 ChildComponent

 }

}

&lt;/script&gt;

				
			

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

				
					
[secondary_label Output]

&lt;div&gt;

 &lt;p&gt;This is the parent component with slot data.&lt;/p&gt;

 &lt;div&gt;

 &lt;p&gt;This is the child component.&lt;/p&gt;

 &lt;p&gt;Slot Content&lt;/p&gt;

 &lt;div&gt;

 &lt;p&gt;This is the parent component without slot data.&lt;/p&gt;

 &lt;div&gt;

 &lt;p&gt;This is the child component.&lt;/p&gt;

 &lt;p&gt;Fallback Content&lt;/p&gt;

 &lt;div&gt;

&lt;/div&gt;

				
			

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:

				
					
&lt;slot name="slotName"&gt;&lt;/slot&gt;

				
			

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

				
					
[label ChildComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;main&gt;

 &lt;slot name="main"&gt;&lt;/slot&gt;

 &lt;/main&gt;

 &lt;aside&gt;

 &lt;slot name="aside"&gt;&lt;/slot&gt;

 &lt;/aside&gt;

 &lt;slot&gt;&lt;/slot&gt;

 &lt;/div&gt;

&lt;/template&gt;

				
			

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

				
					
[label ParentComponent.vue]

&lt;template&gt;

 &lt;div&gt;

 &lt;ChildComponent&gt;

 &lt;template v-slot:main&gt;

 &lt;p&gt;Custom Main&lt;/p&gt;

 &lt;/template&gt;

 &lt;template v-slot:aside&gt;

 &lt;p&gt;Custom Aside&lt;/p&gt;

 &lt;/template&gt;

 &lt;div&gt;

 &lt;p&gt;Custom Content&lt;/p&gt;

 &lt;/div&gt;

 &lt;/ChildComponent&gt;

 &lt;/div&gt;

&lt;/template&gt;



&lt;script&gt;

import ChildComponent from './ChildComponent.vue';



export default {

 components: {

 ChildComponent

 }

}

&lt;/script&gt;

				
			

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:

				
					
[secondary_label Output]

&lt;div&gt;

 &lt;div&gt;

 &lt;main&gt;

 &lt;p&gt;Custom Main&lt;/p&gt;

 &lt;/main&gt;

 &lt;aside&gt;

 &lt;p&gt;Custom Aside&lt;/p&gt;

 &lt;/aside&gt;

 &lt;p&gt;Custom Errata&lt;/p&gt;

 &lt;div&gt;

&lt;/div&gt;

				
			

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.