Slots
# Slots
# Slot Basics
<div id="root">
<child> <!-- component tag -->
<h1>hello</h1>
</child>
</div>
<script type="text/javascript">
Vue.component('child', { // child component
template: '<div><slot></slot></div>'
})
var vm = new Vue({
el: '#root'
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In the code above, the h1 inside the component tag is the element to be inserted into the child component. The child component uses the slot tag to receive the h1 tag passed from the parent.
# Default Content
Vue.component('child', {
template: '<div><slot>Default content</slot></div>'
})
2
3
The child component's slot tag can contain default content, which is only rendered when the parent does not provide any content.
# Named Slots
Warning
Updated in 2.6.0. The slot attribute syntax has been deprecated.
<div id="root">
<child>
<div slot="header">header</div> <!--old syntax: can use template or other tags-->
<div slot="footer">footer</div>
</child>
</div>
<script type="text/javascript">
Vue.component('child', {
template: `<div>
<slot name="header"></slot>
<div>content</div>
<slot name="footer"></slot>
</div>`
})
var vm = new Vue({
el: '#root'
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In the code above, the component tag has two elements with different slot attribute values. The child component has two slot tags with corresponding name attributes to receive the content passed from the parent.
Tip
Since 2.6.0, use the v-slot directive instead of the slot attribute syntax.
<div id="root">
<child>
<template v-slot:header> <!--new syntax: can only use template tag-->
<h1>Title</h1>
</template>
<p>Content</p>
<template v-slot:footer>
<p>Footer</p>
</template>
</child>
</div>
<script type="text/javascript">
Vue.component('child', {
template: `<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>`
})
var vm = new Vue({
el: '#root'
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Since version 2.6.0, named slots use the v-slot directive instead of the slot tag attribute, e.g. v-slot:header. Inside the child component, slot tags still use the name attribute to receive content. Unnamed slots receive content that does not use v-slot.
Additionally, named slots can also use default content.
Note that v-slot can only be added to <template> tags (with one exception (opens new window)), which is different from the deprecated slot attribute (opens new window).
# Scoped Slots
Warning
Updated in 2.6.0. The slot-scope attribute syntax has been deprecated.
<div id="root">
<child>
<template slot-scope="dataObj"> <!--can use other tags, but they will be included in the slot-->
<li>{{dataObj.dataItem}}</li>
</template>
</child>
</div>
<script type="text/javascript">
Vue.component('child', {
data(){
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot
v-for="item of list"
:dataItem=item
>
</slot>
</ul>
</div>`
})
var vm = new Vue({
el: '#root'
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In the code above, the component tag uses a template tag with the slot-scope attribute to receive values passed from the child component. The li tag inside template is the element inserted into the slot, and dataObj.dataItem data is provided by the child component. The child component uses v-for to loop and insert the li tags provided by the parent, while passing each item via :dataItem=item.
The child component provides the data, the parent component receives the data, processes it, inserts it into elements, and then places the elements into the child component's slot.
# Purpose:
Data is provided by the child component, but the parent decides which elements to render, and can perform secondary processing on the data.
Tip
Since 2.6.0, use v-slot instead of the slot-scope attribute syntax.
To make user available in the parent slot content, we can bind user as an attribute of the <slot> element:
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
2
3
4
5
Attributes bound to a <slot> element are called slot props. Now, in the parent scope, we can use v-slot with a value to define a name for the slot props we've been provided:
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
2
3
4
5
In this example, we chose to name the object containing all slot props as slotProps, but you can use any name you like.
<div id="root">
<child>
<template v-slot:default="dataObj"> <!--default is the default name and can be omitted, but not when there are multiple slots-->
<li>{{dataObj.dataItem}}</li>
</template>
</child>
</div>
<script type="text/javascript">
Vue.component('child', {
data(){
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot
v-for="item of list"
:dataItem=item
>
</slot>
</ul>
</div>`
})
var vm = new Vue({
el: '#root'
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Named Slot Shorthand
Just like v-on and v-bind, v-slot also has a shorthand, replacing everything before the argument (v-slot:) with the character #. For example, v-slot:header can be rewritten as #header:
<base-layout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</base-layout>
2
3
4
5
6
7
8
9
10
11
12
However, just like other directives, the shorthand is only available when an argument is provided. This means the following syntax is invalid:
<!-- This will trigger a warning -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>
2
3
4
If you wish to use the shorthand, you must always specify the slot name instead:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>
2
3