Vue 3 is in beta and it’s subject to change.
Vue 3 is the up and coming version of Vue front end framework.
It builds on the popularity and ease of use of Vue 2.
In this article, we’ll look at how to use slots to populate content with Vue 3.
Named Slots
We can name our slots so that we can have multiple slots in one component.
For instance, we can write:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<blog-post>
<template v-slot:header>
<h1>header</h1>
</template>
<template v-slot:default>
<p>lorem ipsum.</p>
</template>
<template v-slot:footer>
<p>footer</p>
</template>
</blog-post>
</div>
<script>
const app = Vue.createApp({});
app.component("blog-post", {
template: `
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
`
});
app.mount("#app");
</script>
</body>
</html>
The blog-post
component has the header, main, and footer elements.
Inside each, they have their own slots.
We name the top slot
with the name header
.
And we named the bottom slot
with the name footer
.
The main tag has the slot
with no name.
Then we can populate them with the template
element.
The v-slot
directive lets us populate the slots by passing in the slot name as the argument.
If a slot has no name, then we can refer to it with default
.
Therefore, we get the h1 displayed on top.
‘lorem ipsum’ is displayed in the middle.
And ‘footer’ is displayed at the bottom.
Scoped Slots
Scoped slots let us make states from the child element available to the parent.
For example, we can write:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<items>
<template v-slot:default="slotProps">
<b>{{ slotProps.item.name }}</b>
</template>
</items>
</div>
<script>
const app = Vue.createApp({});
app.component("items", {
template: `
<ul>
<li v-for="( item, index ) in items">
<slot v-bind:item="item"></slot>
</li>
</ul>
`,
data() {
return {
items: [{ name: "apple" }, { name: "orange" }, { name: "grape" }]
};
}
});
app.mount("#app");
</script>
</body>
</html>
We have the items
component with the items
that we want to render.
Instead of rendering them directly, we pass them into the slot
with the v-bind
directive so that we can change how they’re rendered in the parent.
The argument of v-bind
will be the property name in the slotProps
variable in the parent’s template.
The value will be the property value of the slotProps.item
property.
Therefore, we can add the template
tag in between the items
tag.
The template
tag has the v-slot:default
directive with the slotProps
value.
And we can use that to customize the rendering of the properties passed in from v-bind
in items
.
If there’s only one slot, then we can shorter the syntax for accessing the lone default slot.
For instance, we can write:
v-slot="slotProps"
instead of:
v-slot:default="slotProps"
So we can have:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<items>
<template v-slot="slotProps">
<b>{{ slotProps.item.name }}</b>
</template>
</items>
</div>
<script>
const app = Vue.createApp({});
app.component("items", {
template: `
<ul>
<li v-for="( item, index ) in items">
<slot v-bind:item="item"></slot>
</li>
</ul>
`,
data() {
return {
items: [{ name: "apple" }, { name: "orange" }, { name: "grape" }]
};
}
});
app.mount("#app");
</script>
</body>
</html>
which is slightly shorter.
Conclusion
We can add named slots to our component and access data from the child in the parent with slot props.