Skip to content

Commit 3f4a190

Browse files
Teleport component guide + API reference (#124)
* feat: finished teleport guide * feat: added Teleport API * Update src/api/built-in-components.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * Update src/api/built-in-components.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * Update src/guide/teleport.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * Update src/guide/teleport.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * Update src/guide/teleport.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * Update src/api/built-in-components.md Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com> * fix: moved h1 to 'wrong' section * fix: typo Co-authored-by: Thorsten Lünborg <t.luenborg@googlemail.com>
1 parent 48303b9 commit 3f4a190

File tree

3 files changed

+136
-6
lines changed

3 files changed

+136
-6
lines changed

src/.vuepress/config.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const sidebar = {
4646
children: [
4747
'/guide/mixins',
4848
'/guide/custom-directive',
49+
'/guide/teleport',
4950
'/guide/render-function',
5051
'/guide/plugins',
5152
'/guide/composition-api-introduction'
@@ -54,9 +55,7 @@ const sidebar = {
5455
{
5556
title: 'Tooling',
5657
collapsable: false,
57-
children: [
58-
'/guide/single-file-component'
59-
]
58+
children: ['/guide/single-file-component']
6059
},
6160
{
6261
title: 'Scaling Up',
@@ -71,9 +70,7 @@ const sidebar = {
7170
{
7271
title: 'Tooling',
7372
collapsable: false,
74-
children: [
75-
'/guide/testing'
76-
]
73+
children: ['/guide/testing']
7774
},
7875
{
7976
title: 'Migration to Vue 3',

src/api/built-in-components.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,32 @@
215215
For detailed usage, see the guide section linked below.
216216

217217
- **See also:** [Content Distribution with Slots](../guide/component-basics.html#content-distribution-with-slots)
218+
219+
## teleport
220+
221+
- **Props:**
222+
223+
- `to` - `string`. Required prop, has to be a valid query selector, or an HTMLElement (if used in a browser environment). Specifies a target element where `<teleport>` content will be moved
224+
225+
```html
226+
<!-- ok -->
227+
<teleport to="#some-id" />
228+
<teleport to=".some-class" />
229+
<teleport to="[data-teleport]" />
230+
231+
<!-- Wrong -->
232+
<teleport to="h1" />
233+
<teleport to="some-string" />
234+
```
235+
236+
- `disabled` - `boolean`. This optional prop can be used to disable the `<teleport>`'s functionality, which means that its slot content will not be moved anywhere and instead be rendered where you specified the `<teleport>` in the surrounding parent component.
237+
238+
```html
239+
<teleport to="#popup" :disabled="displayVideoInline">
240+
<video src="./my-movie.mp4">
241+
</teleport>
242+
```
243+
244+
Notice that this will move the actual DOM nodes instead of being destroyed and recreated, and it will keep any component instances alive as well. All stateful HTML elements (i.e. a playing video) will keep their state.
245+
246+
- **See also:** [Teleport component](../guide/teleport.html#teleport)

src/guide/teleport.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Teleport
2+
3+
Vue encourages us to build our UIs by encapsulating UI and related behavior into components. We can nest them inside one another to build a tree that makes up an application UI.
4+
5+
However, sometimes a part of a component's template belongs into this component logically, while from a technical point of view, it would be preferable to move this part of the template somewhere else in the DOM, outside of Vue app. For example, due to styling requirements, we want to move `<p id="content">` from it's deeply nested position to the `<div>` with `id="endofbody"`
6+
7+
```html
8+
<body>
9+
<div id="app" class="demo">
10+
<h3>Move the #content with the portal component</h3>
11+
<div>
12+
<p id="content">
13+
This should be moved to #endofbody.
14+
</p>
15+
<span>This content should be nested</span>
16+
</div>
17+
</div>
18+
<div id="endofbody"></div>
19+
</body>
20+
```
21+
22+
To do so, we can use Vue's built-in `<teleport>` component:
23+
24+
```html
25+
<body>
26+
<div id="app" class="demo">
27+
<h3>Move the #content with the portal component</h3>
28+
<div>
29+
<teleport to="#endofbody">
30+
<p id="content">
31+
This should be moved to #endofbody.
32+
</p>
33+
</teleport>
34+
<span>This content should be nested</span>
35+
</div>
36+
</div>
37+
<div id="endofbody"></div>
38+
</body>
39+
```
40+
41+
As a result, we will have `teleport` content moved in the rendered DOM tree:
42+
43+
<p class="codepen" data-height="300" data-theme-id="39028" data-default-tab="html,result" data-user="Vue" data-slug-hash="WNrXYXd" data-preview="true" data-editable="true" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Teleport">
44+
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/WNrXYXd">
45+
Teleport</a> by Vue (<a href="https://codepen.io/Vue">@Vue</a>)
46+
on <a href="https://codepen.io">CodePen</a>.</span>
47+
</p>
48+
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
49+
50+
As you can see, all of the children of `<teleport>` will be appended to `<div id="endofbody">`.
51+
52+
## Using with Vue components
53+
54+
If `<teleport>` contains a Vue component, it will remain a logical child component of the `<teleport>`'s parent:
55+
56+
```js
57+
const app = Vue.createApp({
58+
template: `
59+
<h1>Root instance</h1>
60+
<parent-component />
61+
`
62+
})
63+
64+
app.component('parent-component', {
65+
template: `
66+
<h2>This is a parent component</h2>
67+
<teleport to="#endofbody">
68+
<child-component name="John" />
69+
</teleport>
70+
`
71+
})
72+
73+
app.component('child-component', {
74+
props: ['name'],
75+
template: `
76+
<div>Hello, {{ name }}</div>
77+
`
78+
})
79+
```
80+
81+
In this case, even when `child-component` is rendered in the different place, it will remain a child of `parent-component` and will receive a `name` prop from it.
82+
83+
This also means that injections from a parent component work as expected, and that the child component will be nested below the parent component in the Vue Devtools, instead of being placed where the actual content moved to.
84+
85+
## Using multiple teleports on the same target
86+
87+
A common use case scenario would be a reusable `<Modal>` component of which there might be multiple instances active at the same time. For this kind of scenario, multiple `<teleport>` components can mount their content to the same target element. The order will be a simple append - later mounts will be located after earlier ones within the target element.
88+
89+
```html
90+
<teleport to="#modals">
91+
<div>A</div>
92+
</teleport>
93+
<teleport to="#modals">
94+
<div>B</div>
95+
</teleport>
96+
97+
<!-- result-->
98+
<div id="modals">
99+
<div>A</div>
100+
<div>B</div>
101+
</div>
102+
```
103+
104+
You can check `<teleport>` component options in the [API reference](../api/built-in-components.html#teleport)

0 commit comments

Comments
 (0)