Vue.js is a popular JavaScript framework used for building user interfaces. One important aspect of Vue.js is understanding how to use slots. With the recent release of Vue 3, the syntax for using slots has been made more succinct.
This change to slots has gotten me re-interested in discovering the potential power of slots to provide reusability, and clearer readability to our Vue-based projects.
With Vue slots, you can turn a part or all of your components into reusable templates that will render differently based on different use cases. All you need to do is embed them in slots.
In this article, I’ll help you understand the concept of Vue slots and show you how to use them.
What are slots
Slots in Vue.js are a powerful feature that allows components to be reused and display dynamic content. Slots allow you to pass content into a component and define how it is displayed. This can make your code more modular and reusable, allowing you to create complex applications with ease. Slots are the Vue equivalent to transclusion in Angular and child props in React.
Types of slots
In Vue.js, there are basically two types of slots:
- Default slots
- Named slots.
Overview of slots
We understand the whole concept from the definition of slots — it’s about making components reusable. The best way to understand them is to see them in action. Let’s start with a simple example:
// example.vue
<template>
<div class="example">
<slot></slot>
</div>
</template>
The component above has a wrapper div
. Let’s assume that div
is there to create a stylistic frame around its content. This component is able to be used generically to wrap a frame around any content you want. Let’s see what it looks like to use it.
// app.vue
<template>
<example><img src="logo.png"></example>
</template>
The content that is between the opening and closing example tags will get inserted into the example component where the slot is, replacing the slot tags. This is the most basic way of doing it. It will look like this:
You can also specify default content to go into a slot simply by filling it in:
// example.vue
<template>
<div class="example">
<slot>This is the default content if nothing gets specified to go here</slot>
</div>
</template>
So now if we use it like this instead:
// app.vue
<template>
<example />
</template>
The default text of “This is the default content if nothing gets specified to go here” will show up, but if we use it as we did before, the default text will be overridden by the img
tag:
Default slots
Default slots are a way to pass content from the parent component to a child component. The content passed to a default slot is rendered inside the child component, allowing the parent component to customize the content of the child component.
A default slot is defined in the child component template using the element without a name
attribute. When using a default slot, the content passed from the parent component is placed directly inside the child component, replacing the element.
For example, consider a Card component that contains a header
, main content
area, and footer
:
//Mycard.vue
<template>
<div class="card">
<header class="card-header">
<slot name="header"></slot>
</header>
<main class="card-main">
<slot></slot>
</main>
<footer class="card-footer">
<slot name="footer"></slot>
</footer>
</div>
</template>
<style>
.card {
border: 1px solid lightgray;
border-radius: 5px;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
width: 300px;
height: 200px;
display: flex;
flex-direction: column;
}
.card-header,
.card-footer {
background-color: lightgray;
padding: 1rem;
text-align: center;
}
.card-main {
flex-grow: 1;
background-color: lightyellow;
padding: 1rem;
}
</style>
This component creates a card with a header, main content area, and footer. The default slot is defined in the main
section, where the content passed from the parent component will be rendered.
To pass content to the default slot, the parent component uses the child component in its template, placing the content directly inside:
//app.vue
<template>
<MyCard>
Main Content
</MyCard>
</template>
<script>
import MyCard from './MyCard.vue';
export default {
components: {
MyCard,
},
};
</script>
The content Main Content
will be rendered in the main section of the Card
component as shown below:
Named Slots
The best way to organize a slot-based component system is to name your slots. Named slots are a way to pass content from the parent component to a child component, similar to default slots. However, named slots allow the parent component to specifically target and customize different parts of the child component.
A named slot is defined in the child component template using the <slot>
element with a name attribute. The name attribute specifies the name of the slot and is used by the parent component to target and customize that specific part of the child component.
For example, consider a component called MyLayout
:
//MyLayout.vue
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<style>
.layout {
display: flex;
flex-direction: column;
height: 100vh;
}
header,
footer {
background-color: lightgray;
padding: 1rem;
}
main {
flex-grow: 1;
background-color: lightyellow;
padding: 1rem;
}
</style>
This component creates a layout with a header
, main content
area, and footer
. The named slots are defined in the header and footer sections, where the content passed from the parent component will be rendered.
To pass content to a named slot, the parent component uses the child component in its template and specifies the name of the slot using the v-slot
directive:
//app.vue
<template>
<MyLayout>
<template v-slot:header>
<h1>Header</h1>
</template>
<p>Main Content</p>
<template v-slot:footer>
<h1>Footer</h1>
</template>
</MyLayout>
</template>
<script>
import MyLayout from './MyLayout.vue';
export default {
components: {
MyLayout,
},
};
</script>
The content Header will be rendered in the header section of MyLayout component, and the content Footer will be rendered in the footer section. The content Main Content will be rendered in the default slot, which is located in the main section just like below:
Reusability with slots
Props are a great way to reuse components, but they have their limitations depending on your use case. Props tend to work best in components that have the same format and content, but just different values.
Sometimes you need to make your components a little more flexible and adaptable: maybe you want some components to have certain sections while depending on the page it’s on, you want to remove other sections.
By injecting your content using slots, it makes it easier to switch around the content of a component without having to worry about using template logic to handle rendering.
Conclusion
While Vue slots are a pretty simple concept, it’s super powerful in designing amazing components. We have seen the different ways to reuse properties of a component by using the slot property. This takes component-based development to a whole new level, and while I’ve demonstrated a lot of great ways slots can be used, there are countless more out there. Feel free to explore them.
You can read more about Vue slots on Vue’s official site.
Top comments (2)
Thank you for sharing 👏🏿
you're welcome!