You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
8
8
9
+
> In 2.6.0, we introduced a new unified syntax (the `v-slot` directive) for named slots and scoped slots. It replaces the `slot` and `slot-scope` syntax which is still documented [here](#Legacy-Syntax). The rationale for introducing the new syntax is described in this [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md).
10
+
9
11
## Slot Content
10
12
11
-
Vue implements a content distribution API that's modeled after the current[Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the `<slot>` element to serve as distribution outlets for content.
13
+
Vue implements a content distribution API inspired by the [Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the `<slot>` element to serve as distribution outlets for content.
12
14
13
15
This allows you to compose components like this:
14
16
@@ -51,6 +53,34 @@ Or even other components:
51
53
52
54
If `<navigation-link>` did **not** contain a `<slot>` element, any content passed to it would simply be discarded.
53
55
56
+
## Compilation Scope
57
+
58
+
When you want to use data inside a slot, such as in:
59
+
60
+
```html
61
+
<navigation-linkurl="/profile">
62
+
Logged in as {{ user.name }}
63
+
</navigation-link>
64
+
```
65
+
66
+
That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template. The slot does **not** have access to `<navigation-link>`'s scope. For example, trying to access `url` would not work. As a rule, remember that:
67
+
68
+
> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.
69
+
70
+
## Fallback Content
71
+
72
+
There are cases when it's useful to provide a slot with fallback content, which is rendered when the parent did not provide content for the slot. For example, a `<submit-button>` component might want the content of the button to be "Submit" by default, but also allow users to override with "Save", "Upload", or anything else.
73
+
74
+
To achieve this, specify the fallback content in between the `<slot>` tags in your component's template:
75
+
76
+
```html
77
+
<buttontype="submit">
78
+
<slot>Submit</slot>
79
+
</button>
80
+
```
81
+
82
+
The fallback content "Submit" only gets rendered if the parent did not provide any slot content.
83
+
54
84
## Named Slots
55
85
56
86
There are times when it's useful to have multiple slots. For example, in a hypothetical `base-layout` component with the following template:
@@ -85,145 +115,288 @@ For these cases, the `<slot>` element has a special attribute, `name`, which can
85
115
</div>
86
116
```
87
117
88
-
To provide content to named slots, we can use the `slot` attribute on a `<template>` element in the parent:
118
+
A `<slot>` outlet without `name` implicitly has the name "default".
119
+
120
+
To provide content to named slots, we can use the `v-slot` directive on a `<template>` element in the parent, using the directive argument to indicate which named slot the content is being passed to:
89
121
90
122
```html
91
123
<base-layout>
92
-
<templateslot="header">
124
+
<templatev-slot:header>
93
125
<h1>Here might be a page title</h1>
94
126
</template>
95
127
96
-
<p>A paragraph for the main content.</p>
97
-
<p>And another one.</p>
128
+
<templatev-slot:default>
129
+
<p>A paragraph for the main content.</p>
130
+
<p>And another one.</p>
131
+
</template>
98
132
99
-
<templateslot="footer">
133
+
<templatev-slot:footer>
100
134
<p>Here's some contact info</p>
101
135
</template>
102
136
</base-layout>
103
137
```
104
138
105
-
Or, the `slot` attribute can also be used directly on a normal element:
139
+
Note that unlike the legacy `slot` attribute, `v-slot` must appear on a `<template>` wrapper when being used to denote named slots. The only exception is when used directly on a component tag to denote a [default slot with props](#Default-Slot-with-Props).
106
140
107
-
```html
141
+
### Named Slots Shorthand
142
+
143
+
Similar to `v-on` and `v-bind`, `v-slot` also has a shorthand, replacing everything before the argument with the special symbol `#`. The above example can also be written as:
144
+
145
+
```html
108
146
<base-layout>
109
-
<h1slot="header">Here might be a page title</h1>
147
+
<template#header>
148
+
<h1>Here might be a page title</h1>
149
+
</template>
110
150
111
-
<p>A paragraph for the main content.</p>
112
-
<p>And another one.</p>
151
+
<template#default>
152
+
<p>A paragraph for the main content.</p>
153
+
<p>And another one.</p>
154
+
</template>
113
155
114
-
<pslot="footer">Here's some contact info</p>
156
+
<template#footer>
157
+
<p>Here's some contact info</p>
158
+
</template>
115
159
</base-layout>
116
160
```
117
161
118
-
There can still be one unnamed slot, which is the **default slot** that serves as a catch-all outlet for any unmatched content. In both examples above, the rendered HTML would be:
162
+
### Dynamic Slot Names
163
+
164
+
Dynamic directive arguments also work on `v-slot`:
119
165
120
166
```html
121
-
<divclass="container">
122
-
<header>
123
-
<h1>Here might be a page title</h1>
124
-
</header>
125
-
<main>
126
-
<p>A paragraph for the main content.</p>
127
-
<p>And another one.</p>
128
-
</main>
129
-
<footer>
130
-
<p>Here's some contact info</p>
131
-
</footer>
132
-
</div>
167
+
<base-layout>
168
+
<templatev-slot:[dynamicSlotName]>
169
+
...
170
+
</template>
171
+
172
+
<!-- shorthand equivalent -->
173
+
<template#[anotherSlotName]>
174
+
...
175
+
</template>
176
+
</base-layout>
133
177
```
134
178
135
-
## Default Slot Content
179
+
## Slot Props
136
180
137
-
There are cases when it's useful to provide a slot with default content. For example, a `<submit-button>`component might want the content of the button to be "Submit" by default, but also allow users to override with "Save", "Upload", or anything else.
181
+
So far we have seen that the slot feature allows a child component to compose content passed from the parent with its own template. However, in some cases the child component may wish to customize the slot content based on its own data, which the parent has no access to. It would be great if the child can pass props to `<slot>` outlets. Imagine we have a `<slot-example>` component with the following template:
138
182
139
-
To achieve this, specify the default content in between the `<slot>` tags in your component's template:
183
+
```html
184
+
<!-- slot-example -->
185
+
<span>
186
+
<slotv-bind:msg="myMessage"></slot>
187
+
</span>
188
+
```
140
189
141
-
```html
142
-
<buttontype="submit">
143
-
<slot>Submit</slot>
144
-
</button>
190
+
In order to receive and make use of the props being passed to a slot, the parent component declares the props received using the attribute value of the `v-slot` directive:
191
+
192
+
```html
193
+
<slot-example>
194
+
<templatev-slot:default="slotProps">
195
+
{{ slotProps.msg }}
196
+
</template>
197
+
</slot-example>
145
198
```
146
199
147
-
If the slot is provided content by the parent, it will replace the default content.
200
+
Here you can name `slotProps` anything you like, just like declaring a function argument in JavaScript. The declared variable will become available inside the scope of the slot's `<template>`.
148
201
149
-
## Compilation Scope
202
+
Slots that expect props are also known as "scoped slots", as they create a "scope" within which the received props can be used.
150
203
151
-
When you want to use data inside a slot, such as in:
204
+
<pclass="tip">The `v-slot` syntax is introduced in 2.6.0 and is not supported in older versions. The legacy `slot` and `slot-scope` syntax is still supported in 2.6, and is documented [here](#Legacy-Syntax).</p>
205
+
206
+
### Default Slot with Props
207
+
208
+
When there is only the default slot, the `v-slot` directive can be placed directly on the component itself, and the `default` argument can also be omitted. The above example can thus be simplified to:
152
209
153
210
```html
154
-
<navigation-linkurl="/profile">
155
-
Logged in as {{ user.name }}
156
-
</navigation-link>
211
+
<slot-examplev-slot="slotProps">
212
+
{{ slotProps.msg }}
213
+
</slot-example>
157
214
```
158
215
159
-
That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template. The slot does **not** have access to `<navigation-link>`'s scope. For example, trying to access `url` would not work. As a rule, remember that:
216
+
### Slot Props Destructuring
160
217
161
-
> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.
218
+
The value of `v-slot` can actually accept any valid JavaScript expression that can appear in the argument position of a function definition. This means in supported environments ([single-file components](single-file-components.html) or [modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility)) you can also use [ES2015 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring)in the expression, like so:
162
219
163
-
## Scoped Slots
220
+
```html
221
+
<slot-examplev-slot="{ msg }">
222
+
{{ msg }}
223
+
</slot-example>
224
+
```
225
+
226
+
This can make the template much cleaner when the slot expects a lot of props.
227
+
228
+
Conceptually, the syntax is similar to argument destructuring in JavaScript:
229
+
230
+
```js
231
+
functionCustomText({ text }) {
232
+
return text
233
+
}
234
+
```
164
235
165
-
> New in 2.1.0+
236
+
### Todo List Example
166
237
167
-
Sometimes you'll want to provide a component with a reusable slot that can access data from the child component. For example, a simple `<todo-list>` component may contain the following in its template:
238
+
**Slot props allow us to turn slots into reusable templates that can render different content based on input props.** This is most useful when you are designing a reusable component that encapsulates data logic while allowing the consuming parent component to customize part of its layout.
239
+
240
+
For example, we are implementing a `<todo-list>` component that contains the layout and filtering logic for a list:
168
241
169
242
```html
170
243
<ul>
171
244
<li
172
-
v-for="todo in todos"
245
+
v-for="todo in filteredTodos"
173
246
v-bind:key="todo.id"
174
247
>
175
248
{{ todo.text }}
176
249
</li>
177
250
</ul>
178
251
```
179
252
180
-
But in some parts of our app, we want the individual todo items to render something different than just the `todo.text`. This is where scoped slots come in.
181
-
182
-
To make the feature possible, all we have to do is wrap the todo item content in a `<slot>` element, then pass the slot any data relevant to its context: in this case, the `todo` object:
253
+
Instead of hard-coding how each todo looks like, we can let the parent component take control by making each todo a slot, and passing in the `todo` as a slot prop:
183
254
184
255
```html
185
256
<ul>
186
257
<li
187
-
v-for="todo in todos"
258
+
v-for="todo in filteredTodos"
188
259
v-bind:key="todo.id"
189
260
>
190
261
<!-- We have a slot for each todo, passing it the -->
191
262
<!-- `todo` object as a slot prop. -->
192
-
<slotv-bind:todo="todo">
263
+
<slotname="todo"v-bind:todo="todo">
193
264
<!-- Fallback content -->
194
265
{{ todo.text }}
195
266
</slot>
196
267
</li>
197
268
</ul>
198
269
```
199
270
200
-
Now when we use the `<todo-list>` component, we can optionally define an alternative `<template>` for todo items, but with access to data from the child via the `slot-scope` attribute:
271
+
Now when we use the `<todo-list>` component, we can optionally define an alternative `<template>` for todo items, but with access to data from the child:
201
272
202
273
```html
203
274
<todo-listv-bind:todos="todos">
204
-
<!-- Define `slotProps` as the name of our slot scope -->
205
-
<templateslot-scope="slotProps">
206
-
<!-- Define a custom template for todo items, using -->
207
-
<!-- `slotProps` to customize each todo. -->
208
-
<spanv-if="slotProps.todo.isComplete">✓</span>
209
-
{{ slotProps.todo.text }}
275
+
<templatev-slot:todo="{ todo }">
276
+
<spanv-if="todo.isComplete">✓</span>
277
+
{{ todo.text }}
210
278
</template>
211
279
</todo-list>
212
280
```
213
281
214
-
> In 2.5.0+, `slot-scope` is no longer limited to the `<template>` element, but can instead be used on any element or component in the slot.
282
+
Admitted, the above example is still contrived. A more real-world use case would be a reusable list component that encapsulates the logic of fetching items from an API with infinite scroll, and lets the parent customize how each fetched item should be rendered:
The `v-slot` directive was introduced in Vue 2.6.0, replacing the legacy `slot` + `slot-scope` syntax. The rationale for introducing the new syntax is described in this [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md). The legacy syntax is still supported in 2.6 and will continue to be supported in all future 2.x releases, but is marked for deprecation and will eventually be removed in a future major release.
299
+
300
+
### Named Slots with `slot`
217
301
218
-
The value of `slot-scope` can actually accept any valid JavaScript expression that can appear in the argument position of a function definition. This means in supported environments ([single-file components](single-file-components.html) or [modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility)) you can also use [ES2015 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) in the expression, like so:
302
+
To pass content to named slots from the parent, use the special `slot` attribute on `<template>` (Using the `<base-layout>` component described [here](#Named-Slots) as example):
303
+
304
+
```html
305
+
<base-layout>
306
+
<templateslot="header">
307
+
<h1>Here might be a page title</h1>
308
+
</template>
309
+
310
+
<p>A paragraph for the main content.</p>
311
+
<p>And another one.</p>
312
+
313
+
<templateslot="footer">
314
+
<p>Here's some contact info</p>
315
+
</template>
316
+
</base-layout>
317
+
```
318
+
319
+
Or, the `slot` attribute can also be used directly on a normal element:
320
+
321
+
```html
322
+
<base-layout>
323
+
<h1slot="header">Here might be a page title</h1>
324
+
325
+
<p>A paragraph for the main content.</p>
326
+
<p>And another one.</p>
327
+
328
+
<pslot="footer">Here's some contact info</p>
329
+
</base-layout>
330
+
```
331
+
332
+
There can still be one unnamed slot, which is the **default slot** that serves as a catch-all outlet for any unmatched content. In both examples above, the rendered HTML would be:
333
+
334
+
```html
335
+
<divclass="container">
336
+
<header>
337
+
<h1>Here might be a page title</h1>
338
+
</header>
339
+
<main>
340
+
<p>A paragraph for the main content.</p>
341
+
<p>And another one.</p>
342
+
</main>
343
+
<footer>
344
+
<p>Here's some contact info</p>
345
+
</footer>
346
+
</div>
347
+
```
348
+
349
+
### Scoped Slots with `slot-scope`
350
+
351
+
To receive props passed to a slot, the parent component can use `<template>` with the `slot-scope` special attribute (Using the `<slot-example>` described [here](#Slot-Props) as example):
352
+
353
+
```html
354
+
<slot-example>
355
+
<templateslot="default"slot-scope="slotProps">
356
+
{{ slotProps.msg }}
357
+
</template>
358
+
</slot-example>
359
+
```
360
+
361
+
Here `slot-scope` declares the received props object as the `slotProps` variable, and makes it available inside the `<template>` scope. You can name `slotProps` anything you like similar to naming function arguments in JavaScript.
362
+
363
+
Here `slot="default"` can be omitted as it is implied:
364
+
365
+
```html
366
+
<slot-example>
367
+
<templateslot-scope="slotProps">
368
+
{{ slotProps.msg }}
369
+
</template>
370
+
</slot-example>
371
+
```
372
+
373
+
`slot-scope` can also be used directly on a non `<template>` element (including components):
374
+
375
+
```html
376
+
<slot-example>
377
+
<spanslot-scope="slotProps">
378
+
{{ slotProps.msg }}
379
+
</span>
380
+
</slot-example>
381
+
```
382
+
383
+
The value of `slot-scope` can accept any valid JavaScript expression that can appear in the argument position of a function definition. This means in supported environments ([single-file components](single-file-components.html) or [modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility)) you can also use [ES2015 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) in the expression, like so:
384
+
385
+
```html
386
+
<slot-example>
387
+
<spanslot-scope="{ msg }">
388
+
{{ msg }}
389
+
</span>
390
+
</slot-example>
391
+
```
392
+
393
+
Using the `<todo-list>` described [here](#Todo-List-Example) as example, here's the equivalent usage using `slot-scope`:
219
394
220
395
```html
221
396
<todo-listv-bind:todos="todos">
222
-
<templateslot-scope="{ todo }">
397
+
<templateslot="todo"slot-scope="{ todo }">
223
398
<spanv-if="todo.isComplete">✓</span>
224
399
{{ todo.text }}
225
400
</template>
226
401
</todo-list>
227
402
```
228
-
229
-
This is a great way to make scoped slots a little cleaner.
0 commit comments