Vue 3 — Named Slots and Slot Props
By: John Au-Yeung
Tags: JavaScript, Software Development, Programming, Technology, Web Development

Photo by Mohammed Kabir on Unsplash

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.

Photo by DEAR on Unsplash

Conclusion

We can add named slots to our component and access data from the child in the parent with slot props.

Enjoyed this article? If so, get more similar content by subscribing to Decoded, our YouTube channel!