Defining default content for a slot
In the event that your component has content that works as a good default, this can be accomplished by defining the default content within the slot
element of your component. For example, if you wanted a button to have the text of “Submit” by default, you could do this with the following snippet:
📄BaseButton.vue
<template>
<button class="button">
<slot>Submit</slot>
</button>
</template>
And whenever content is provided to the component, it will automatically override the default content as you would expect.
What are named slots?
Named slots is a way to configure your slots so that they are unique from one another. To do this, slots have a name
property that allows you to designate it with a custom identifier.
In a custom layout component where you need to provide the flexibility to add whatever content required to the header, main, and footer section, this could be accomplished with the following snippet:
📄CustomLayout.vue
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
But the question you may be wondering next is, how would this look when using the CustomLayout
component? To accomplish this, we’ll need the template
element.
What is the template block?
Similar to how you use the <template>
block to define the HTML of your single file components, you can also use it to define specific blocks of HTML that need to be passed into a slot. In order to do this, you need to apply the v-slot
directive.
The v-slot
directive can then take an argument which is the desired slot name you want the content to appear in.
📄App.vue
<template>
<CustomLayout>
<template v-slot:header>
<p>Header content</p>
</template>
<template>
<p>Main body content</p>
</template>
<template v-slot:footer>
<p>Footer content</p>
</template>
</CustomLayout>
</template>
What if I need to programmatically generate slot names?
While things like layouts are often fixed, there are situations we need to programmatically generate our slots. For example, an application may allow users to customize the layout, which is saved on the backend and our Vue.js application renders out what the API returns to us. In this case, we can use dynamic slot names to accomplish this.
The syntax is similar to how you would normally use slot names, except instead of passing the name of the slot, you pass a variable by wrapped in square brackets.
// Normal named slot
<template v-slot:header>...</template>
// Dynamic named slot
<template v-slot:[dynamicSlotNameVariable]>...</template>
Using our BlogLayout
example, here’s how you would programmatically generate the slot names.
📄App.vue
<script>
export default {
data() {
return {
layout: [
{ name: 'header', content: 'My Blog Title' },
{ name: 'body', content: 'Main body content' },
{ name: 'footer', content: 'Footer contet' }
]
}
}
}
</script>
<template>
<BlogLayout>
<template
v-for="section in layout"
v-slot:[section.name]
:key="`blog-section-${section.name}`"
>
{{ section.content }}
</template>
</BlogLayout>
</template>
Does slots have a shorthand syntax?
Similar to v-bind
and v-on
, v-slot
also has a shorthand syntax as well: #
. Using the previous example, this is how the code would look instead.
📄App.vue
<template>
<CustomLayout>
<template #header>
<p>Header content</p>
</template>
<template>
<p>Main body content</p>
</template>
<template #footer>
<p>Footer content</p>
</template>
</CustomLayout>
</template>
However, from my personal experience, I would caution against using this shorthand in your codebase as it can cause confusion with users who are not as familiar with slots. It can easily be mistaken for a CSS ID rather than something specific to the slot API in Vue. So use with caution!