Skip to content

Commit 1ae1bec

Browse files
committed
slots wip
1 parent f83e6f9 commit 1ae1bec

File tree

4 files changed

+153
-145
lines changed

4 files changed

+153
-145
lines changed

src/guide/components/slots.md

Lines changed: 122 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,83 @@
1+
---
2+
aside: deep
3+
---
4+
15
# Slots
26

37
> This page assumes you've already read the [Components Basics](/guide/essentials/component-basics). Read that first if you are new to components.
48
5-
## Slot Content
9+
## Slot Content and Outlet
610

7-
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.
11+
We have learned that components can accept props, which can be JavaScript values of any type. But how about template content? In some cases, we may want to pass a template fragment to a child component, and let the child component render the fragment within its own template.
812

9-
This allows you to compose components like this:
13+
For example, we may have a `<FancyButton>` component that supports usage like this:
1014

11-
```vue-html
12-
<todo-button>
13-
Add todo
14-
</todo-button>
15+
```vue-html{2}
16+
<FancyButton>
17+
Click me! <!-- slot content -->
18+
</FancyButton>
1519
```
1620

17-
Then in the template for `<todo-button>`, you might have:
21+
This is how the template of `<FancyButton>` looks like:
1822

19-
```vue-html
20-
<!-- todo-button component template -->
21-
<button class="btn-primary">
22-
<slot></slot>
23+
```vue-html{2}
24+
<button class="fancy-btn">
25+
<slot></slot> <!-- slot outlet -->
2326
</button>
2427
```
2528

26-
When the component renders, `<slot></slot>` will be replaced by "Add Todo".
29+
Notice the `<slot>` element, which is a **slot outlet** that indicates where the parent-provided **slot content** should be rendered.
2730

28-
```vue-html
29-
<!-- rendered HTML -->
30-
<button class="btn-primary">
31-
Add todo
32-
</button>
33-
```
31+
![slot diagram](/images/slots.png)
3432

35-
Strings are just the beginning though! Slots can also contain any template code, including HTML:
33+
And the final rendered DOM:
3634

37-
```vue-html
38-
<todo-button>
39-
<!-- Add a Font Awesome icon -->
40-
<i class="fas fa-plus"></i>
41-
Add todo
42-
</todo-button>
35+
```html
36+
<button class="fancy-btn">Click me!</button>
4337
```
4438

45-
Or even other components:
39+
With slots, the `<FancyButton>` is responsible for rendering the outer `<button>` (and its fancy styling), while the inner content is determined by the parent component using `<FancyButton>`. This makes our `<FancyButton>` more flexible and reusable, since we can now use it in different places with different inner content, but all with the same fancy styling.
4640

47-
```vue-html
48-
<todo-button>
49-
<!-- Use a component to add an icon -->
50-
<font-awesome-icon name="plus"></font-awesome-icon>
51-
Add todo
52-
</todo-button>
53-
```
54-
55-
If `<todo-button>`'s template did **not** contain a `<slot>` element, any content provided between its opening and closing tag would be discarded.
41+
Slot content is not just limited to text. It can be any valid template content. For example, we can pass in elements or even other components:
5642

5743
```vue-html
58-
<!-- todo-button component template -->
59-
60-
<button class="btn-primary">
61-
Create a new item
62-
</button>
44+
<FancyButton>
45+
<span style="color:red">Click me!</span>
46+
<AwesomeIcon name="plus" />
47+
</FancyButton>
6348
```
6449

65-
```vue-html
66-
<todo-button>
67-
<!-- Following text won't be rendered -->
68-
Add todo
69-
</todo-button>
70-
```
50+
<div class="composition-api">
7151

72-
## Render Scope
52+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCBGYW5jeUJ1dHRvbiBmcm9tICcuL0ZhbmN5QnV0dG9uLnZ1ZSdcbmltcG9ydCBBd2Vzb21lSWNvbiBmcm9tICcuL0F3ZXNvbWVJY29uLnZ1ZSdcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxGYW5jeUJ1dHRvbj5cbiAgICBDbGljayBtZVxuIFx0PC9GYW5jeUJ1dHRvbj5cblxuICA8RmFuY3lCdXR0b24+XG4gICAgPHNwYW4gc3R5bGU9XCJjb2xvcjpyZWRcIj5DbGljayBtZSE8L3NwYW4+XG4gICAgPEF3ZXNvbWVJY29uIC8+XG4gIDwvRmFuY3lCdXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0iLCJGYW5jeUJ1dHRvbi52dWUiOiI8dGVtcGxhdGU+XG4gIDxidXR0b24gY2xhc3M9XCJmYW5jeS1idG5cIj5cbiAgXHQ8c2xvdC8+XG5cdDwvYnV0dG9uPlxuPC90ZW1wbGF0ZT5cblxuPHN0eWxlPlxuLmZhbmN5LWJ0biB7XG4gIGNvbG9yOiAjZmZmO1xuICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoMzE1ZGVnLCAjNDJkMzkyIDI1JSwgIzY0N2VmZik7XG4gIGJvcmRlcjogbm9uZTtcbiAgcGFkZGluZzogMTBweDtcbiAgYm9yZGVyLXJhZGl1czogOHB4O1xufVxuPC9zdHlsZT4iLCJBd2Vzb21lSWNvbi52dWUiOiI8IS0tIHVzaW5nIGFuIGVtb2ppIGp1c3QgZm9yIGRlbW8gcHVycG9zZXMgLS0+XG48dGVtcGxhdGU+4p6VPC90ZW1wbGF0ZT4ifQ==)
7353

74-
When you want to use data inside a slot, such as in:
54+
</div>
55+
<div class="options-api">
7556

76-
```vue-html
77-
<todo-button>
78-
Delete a {{ item.name }}
79-
</todo-button>
80-
```
57+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmltcG9ydCBGYW5jeUJ1dHRvbiBmcm9tICcuL0ZhbmN5QnV0dG9uLnZ1ZSdcbmltcG9ydCBBd2Vzb21lSWNvbiBmcm9tICcuL0F3ZXNvbWVJY29uLnZ1ZSdcbiAgXG5leHBvcnQgZGVmYXVsdCB7XG4gIGNvbXBvbmVudHM6IHsgRmFuY3lCdXR0b24sIEF3ZXNvbWVJY29uIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxGYW5jeUJ1dHRvbj5cbiAgICBDbGljayBtZVxuIFx0PC9GYW5jeUJ1dHRvbj5cblxuICA8RmFuY3lCdXR0b24+XG4gICAgPHNwYW4gc3R5bGU9XCJjb2xvcjpyZWRcIj5DbGljayBtZSE8L3NwYW4+XG4gICAgPEF3ZXNvbWVJY29uIC8+XG4gIDwvRmFuY3lCdXR0b24+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0iLCJGYW5jeUJ1dHRvbi52dWUiOiI8dGVtcGxhdGU+XG4gIDxidXR0b24gY2xhc3M9XCJmYW5jeS1idG5cIj5cbiAgXHQ8c2xvdC8+XG5cdDwvYnV0dG9uPlxuPC90ZW1wbGF0ZT5cblxuPHN0eWxlPlxuLmZhbmN5LWJ0biB7XG4gIGNvbG9yOiAjZmZmO1xuICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoMzE1ZGVnLCAjNDJkMzkyIDI1JSwgIzY0N2VmZik7XG4gIGJvcmRlcjogbm9uZTtcbiAgcGFkZGluZzogMTBweDtcbiAgYm9yZGVyLXJhZGl1czogOHB4O1xufVxuPC9zdHlsZT4iLCJBd2Vzb21lSWNvbi52dWUiOiI8IS0tIHVzaW5nIGFuIGVtb2ppIGp1c3QgZm9yIGRlbW8gcHVycG9zZXMgLS0+XG48dGVtcGxhdGU+4p6VPC90ZW1wbGF0ZT4ifQ==)
58+
59+
</div>
8160

82-
That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template.
61+
Vue components' slot mechanism is inspired by the [native Web Component `<slot>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot), but with additional capabilities that we will see later.
8362

84-
<img src="/images/slot.png" width="447" height="auto" style="display: block; margin: 0 auto; max-width: 100%" loading="lazy" alt="Slot explanation diagram">
63+
## Render Scope
8564

86-
The slot does **not** have access to `<todo-button>`'s scope. For example, trying to access `action` would not work:
65+
Slot content has access to the data scope of the parent component, because it is defined in the parent. For example:
8766

8867
```vue-html
89-
<todo-button action="delete">
90-
Clicking here will {{ action }} an item
91-
<!--
92-
The `action` will be undefined, because this content is passed
93-
_to_ <todo-button>, rather than defined _inside_ the
94-
<todo-button> component.
95-
-->
96-
</todo-button>
68+
<span>{{ message }}</span>
69+
<FancyButton>{{ message }}</FancyButton>
9770
```
9871

99-
As a rule, remember that:
72+
Here both <span v-pre>`{{ message }}`</span> interpolations will render the same content, even though one of them is passed into a child component.
73+
74+
Slot content does **not** have access to the child component's data. As a rule, remember that:
10075

10176
> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.
10277
10378
## Fallback Content
10479

105-
There are cases when it's useful to specify fallback (i.e. default) content for a slot, to be rendered only when no content is provided. For example, in a `<submit-button>` component:
80+
There are cases when it's useful to specify fallback (i.e. default) content for a slot, to be rendered only when no content is provided. For example, in a `<SubmitButton>` component:
10681

10782
```vue-html
10883
<button type="submit">
@@ -112,45 +87,52 @@ There are cases when it's useful to specify fallback (i.e. default) content for
11287

11388
We might want the text "Submit" to be rendered inside the `<button>` most of the time. To make "Submit" the fallback content, we can place it in between the `<slot>` tags:
11489

115-
```vue-html
90+
```vue-html{3}
11691
<button type="submit">
117-
<slot>Submit</slot>
92+
<slot>
93+
Submit <!-- fallback content -->
94+
</slot>
11895
</button>
11996
```
12097

12198
Now when we use `<submit-button>` in a parent component, providing no content for the slot:
12299

123100
```vue-html
124-
<submit-button></submit-button>
101+
<SubmitButton />
125102
```
126103

127-
will render the fallback content, "Submit":
104+
This will render the fallback content, "Submit":
128105

129-
```vue-html
130-
<button type="submit">
131-
Submit
132-
</button>
106+
```html
107+
<button type="submit">Submit</button>
133108
```
134109

135110
But if we provide content:
136111

137112
```vue-html
138-
<submit-button>
139-
Save
140-
</submit-button>
113+
<SubmitButton>Save</SubmitButton>
141114
```
142115

143116
Then the provided content will be rendered instead:
144117

145-
```vue-html
146-
<button type="submit">
147-
Save
148-
</button>
118+
```html
119+
<button type="submit">Save</button>
149120
```
150121

122+
<div class="composition-api">
123+
124+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCBTdWJtaXRCdXR0b24gZnJvbSAnLi9TdWJtaXRCdXR0b24udnVlJ1xuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPCEtLSB1c2UgZmFsbGJhY2sgdGV4dCAtLT5cbiAgPFN1Ym1pdEJ1dHRvbiAvPlxuICBcbiAgPCEtLSBwcm92aWRlIGN1c3RvbSB0ZXh0IC0tPlxuICA8U3VibWl0QnV0dG9uPlNhdmU8L1N1Ym1pdEJ1dHRvbj5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSIsIlN1Ym1pdEJ1dHRvbi52dWUiOiI8dGVtcGxhdGU+XG4gIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlxuXHQgIDxzbG90PlxuICAgIFx0U3VibWl0IDwhLS0gZmFsbGJhY2sgY29udGVudCAtLT5cbiAgXHQ8L3Nsb3Q+XG5cdDwvYnV0dG9uPlxuPC90ZW1wbGF0ZT4ifQ==)
125+
126+
</div>
127+
<div class="options-api">
128+
129+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmltcG9ydCBTdWJtaXRCdXR0b24gZnJvbSAnLi9TdWJtaXRCdXR0b24udnVlJ1xuICBcbmV4cG9ydCBkZWZhdWx0IHtcbiAgY29tcG9uZW50czoge1xuICAgIFN1Ym1pdEJ1dHRvblxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8IS0tIHVzZSBmYWxsYmFjayB0ZXh0IC0tPlxuICA8U3VibWl0QnV0dG9uIC8+XG4gIFxuICA8IS0tIHByb3ZpZGUgY3VzdG9tIHRleHQgLS0+XG4gIDxTdWJtaXRCdXR0b24+U2F2ZTwvU3VibWl0QnV0dG9uPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59IiwiU3VibWl0QnV0dG9uLnZ1ZSI6Ijx0ZW1wbGF0ZT5cbiAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCI+XG5cdCAgPHNsb3Q+XG4gICAgXHRTdWJtaXQgPCEtLSBmYWxsYmFjayBjb250ZW50IC0tPlxuICBcdDwvc2xvdD5cblx0PC9idXR0b24+XG48L3RlbXBsYXRlPiJ9)
130+
131+
</div>
132+
151133
## Named Slots
152134

153-
There are times when it's useful to have multiple slots. For example, in a `<base-layout>` component with the following template:
135+
There are times when it's useful to have multiple slot outlets in a single component. For example, in a `<BaseLayout>` component with the following template:
154136

155137
```vue-html
156138
<div class="container">
@@ -184,28 +166,40 @@ For these cases, the `<slot>` element has a special attribute, `name`, which can
184166

185167
A `<slot>` outlet without `name` implicitly has the name "default".
186168

187-
To provide content to named slots, we need to use the `v-slot` directive on a `<template>` element, providing the name of the slot as `v-slot`'s argument:
169+
In a parent component using `<BaseLayout>`, we need a way to pass multiple slot content framgents, each targeting a different slot outlet. This is where the `v-slot` directive comes in.
170+
171+
`v-slot` must be used on a `<template>`, where it expects an argument correspnding to its target slot's name:
188172

189173
```vue-html
190-
<base-layout>
174+
<BaseLayout>
191175
<template v-slot:header>
176+
<!-- content for the header slot -->
177+
</template>
178+
</BaseLayout>
179+
```
180+
181+
`v-slot` has a dedicated shorthand `#`, so `<template v-slot:header>` can be shortened to just `<template #header>`. It means "render this template fragment in the child component's 'header' slot".
182+
183+
Here's us passing content to all three slots to `<BaseLayout>` using the shorthand syntax:
184+
185+
```vue-html
186+
<BaseLayout>
187+
<template #header>
192188
<h1>Here might be a page title</h1>
193189
</template>
194190
195-
<template v-slot:default>
191+
<template #default>
196192
<p>A paragraph for the main content.</p>
197193
<p>And another one.</p>
198194
</template>
199195
200-
<template v-slot:footer>
196+
<template #footer>
201197
<p>Here's some contact info</p>
202198
</template>
203-
</base-layout>
199+
</BaseLayout>
204200
```
205201

206-
Now everything inside the `<template>` elements will be passed to the corresponding slots.
207-
208-
The rendered HTML will be:
202+
Now everything inside the `<template>` elements will be passed to the corresponding slots. The final rendered HTML will be:
209203

210204
```vue-html
211205
<div class="container">
@@ -222,11 +216,47 @@ The rendered HTML will be:
222216
</div>
223217
```
224218

219+
<div class="composition-api">
220+
221+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCBCYXNlTGF5b3V0IGZyb20gJy4vQmFzZUxheW91dC52dWUnXG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8QmFzZUxheW91dD5cbiAgICA8dGVtcGxhdGUgI2hlYWRlcj5cbiAgICAgIDxoMT5IZXJlIG1pZ2h0IGJlIGEgcGFnZSB0aXRsZTwvaDE+XG4gICAgPC90ZW1wbGF0ZT5cblxuICAgIDx0ZW1wbGF0ZSAjZGVmYXVsdD5cbiAgICAgIDxwPkEgcGFyYWdyYXBoIGZvciB0aGUgbWFpbiBjb250ZW50LjwvcD5cbiAgICAgIDxwPkFuZCBhbm90aGVyIG9uZS48L3A+XG4gICAgPC90ZW1wbGF0ZT5cblxuICAgIDx0ZW1wbGF0ZSAjZm9vdGVyPlxuICAgICAgPHA+SGVyZSdzIHNvbWUgY29udGFjdCBpbmZvPC9wPlxuICAgIDwvdGVtcGxhdGU+XG4gIDwvQmFzZUxheW91dD5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSIsIkJhc2VMYXlvdXQudnVlIjoiPHRlbXBsYXRlPlxuICA8ZGl2IGNsYXNzPVwiY29udGFpbmVyXCI+XG4gICAgPGhlYWRlcj5cbiAgICAgIDxzbG90IG5hbWU9XCJoZWFkZXJcIj48L3Nsb3Q+XG4gICAgPC9oZWFkZXI+XG4gICAgPG1haW4+XG4gICAgICA8c2xvdD48L3Nsb3Q+XG4gICAgPC9tYWluPlxuICAgIDxmb290ZXI+XG4gICAgICA8c2xvdCBuYW1lPVwiZm9vdGVyXCI+PC9zbG90PlxuICAgIDwvZm9vdGVyPlxuICA8L2Rpdj5cbjwvdGVtcGxhdGU+XG5cbjxzdHlsZT5cbiAgZm9vdGVyIHtcbiAgICBib3JkZXItdG9wOiAxcHggc29saWQgI2NjYztcbiAgICBjb2xvcjogIzY2NjtcbiAgICBmb250LXNpemU6IDAuOGVtO1xuICB9XG48L3N0eWxlPiJ9)
222+
223+
</div>
224+
<div class="options-api">
225+
226+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmltcG9ydCBCYXNlTGF5b3V0IGZyb20gJy4vQmFzZUxheW91dC52dWUnXG4gIFxuZXhwb3J0IGRlZmF1bHQge1xuICBjb21wb25lbnRzOiB7XG4gICAgQmFzZUxheW91dFxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8QmFzZUxheW91dD5cbiAgICA8dGVtcGxhdGUgI2hlYWRlcj5cbiAgICAgIDxoMT5IZXJlIG1pZ2h0IGJlIGEgcGFnZSB0aXRsZTwvaDE+XG4gICAgPC90ZW1wbGF0ZT5cblxuICAgIDx0ZW1wbGF0ZSAjZGVmYXVsdD5cbiAgICAgIDxwPkEgcGFyYWdyYXBoIGZvciB0aGUgbWFpbiBjb250ZW50LjwvcD5cbiAgICAgIDxwPkFuZCBhbm90aGVyIG9uZS48L3A+XG4gICAgPC90ZW1wbGF0ZT5cblxuICAgIDx0ZW1wbGF0ZSAjZm9vdGVyPlxuICAgICAgPHA+SGVyZSdzIHNvbWUgY29udGFjdCBpbmZvPC9wPlxuICAgIDwvdGVtcGxhdGU+XG4gIDwvQmFzZUxheW91dD5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSIsIkJhc2VMYXlvdXQudnVlIjoiPHRlbXBsYXRlPlxuICA8ZGl2IGNsYXNzPVwiY29udGFpbmVyXCI+XG4gICAgPGhlYWRlcj5cbiAgICAgIDxzbG90IG5hbWU9XCJoZWFkZXJcIj48L3Nsb3Q+XG4gICAgPC9oZWFkZXI+XG4gICAgPG1haW4+XG4gICAgICA8c2xvdD48L3Nsb3Q+XG4gICAgPC9tYWluPlxuICAgIDxmb290ZXI+XG4gICAgICA8c2xvdCBuYW1lPVwiZm9vdGVyXCI+PC9zbG90PlxuICAgIDwvZm9vdGVyPlxuICA8L2Rpdj5cbjwvdGVtcGxhdGU+XG5cbjxzdHlsZT5cbiAgZm9vdGVyIHtcbiAgICBib3JkZXItdG9wOiAxcHggc29saWQgI2NjYztcbiAgICBjb2xvcjogIzY2NjtcbiAgICBmb250LXNpemU6IDAuOGVtO1xuICB9XG48L3N0eWxlPiJ9)
227+
228+
</div>
229+
225230
Note that **`v-slot` can only be added to a `<template>`** (with [one exception](#abbreviated-syntax-for-lone-default-slots))
226231

232+
## Dynamic Slot Names
233+
234+
[Dynamic directive arguments](/guide/essentials/template-syntax.md#dynamic-arguments) also work on `v-slot`, allowing the definition of dynamic slot names:
235+
236+
```vue-html
237+
<base-layout>
238+
<template v-slot:[dynamicSlotName]>
239+
...
240+
</template>
241+
242+
<!-- with shorthand -->
243+
<template #[dynamicSlotName]>
244+
...
245+
</template>
246+
</base-layout>
247+
```
248+
249+
Do note the expression is subject to the same [syntax constraints](/guide/essentials/template-syntax.html#directives) of dynamic directive arguments.
250+
227251
## Scoped Slots
228252

229-
Sometimes, it's useful for slot content to have access to data only available in the child component. It's a common case when a component is used to render an array of items, and we want to be able to customize the way each item is rendered.
253+
As discussed in [Render Scope](#render-scope), slot content does not have access to state in the child component.
254+
255+
However, there are cases where it could be useful if the child component can selectively expose data to the slot content passed by the parent. For example, we can have a
256+
257+
- Think of scoped slots as callback functions being passed into the child component (in fact, slots are compiled into functions!)
258+
- The child component call the slot function while passing it props
259+
- The slot function use the props to render and return content
230260

231261
For example, we have a component, containing a list of todo-items.
232262

@@ -378,56 +408,3 @@ You can even define fallbacks, to be used in case a slot prop is undefined:
378408
<span class="green">{{ item }}</span>
379409
</todo-list>
380410
```
381-
382-
## Dynamic Slot Names
383-
384-
[Dynamic directive arguments](/guide/essentials/template-syntax.md#dynamic-arguments) also work on `v-slot`, allowing the definition of dynamic slot names:
385-
386-
```vue-html
387-
<base-layout>
388-
<template v-slot:[dynamicSlotName]>
389-
...
390-
</template>
391-
</base-layout>
392-
```
393-
394-
## Named Slots Shorthand
395-
396-
Similar to `v-on` and `v-bind`, `v-slot` also has a shorthand, replacing everything before the argument (`v-slot:`) with the special symbol `#`. For example, `v-slot:header` can be rewritten as `#header`:
397-
398-
```vue-html
399-
<base-layout>
400-
<template #header>
401-
<h1>Here might be a page title</h1>
402-
</template>
403-
404-
<template #default>
405-
<p>A paragraph for the main content.</p>
406-
<p>And another one.</p>
407-
</template>
408-
409-
<template #footer>
410-
<p>Here's some contact info</p>
411-
</template>
412-
</base-layout>
413-
```
414-
415-
However, just as with other directives, the shorthand is only available when an argument is provided. That means the following syntax is invalid:
416-
417-
```vue-html
418-
<!-- This will trigger a warning -->
419-
420-
<todo-list #="{ item }">
421-
<i class="fas fa-check"></i>
422-
<span class="green">{{ item }}</span>
423-
</todo-list>
424-
```
425-
426-
Instead, you must always specify the name of the slot if you wish to use the shorthand:
427-
428-
```vue-html
429-
<todo-list #default="{ item }">
430-
<i class="fas fa-check"></i>
431-
<span class="green">{{ item }}</span>
432-
</todo-list>
433-
```

0 commit comments

Comments
 (0)