Skip to content

Teleport component guide + API reference #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const sidebar = {
children: [
'/guide/mixins',
'/guide/custom-directive',
'/guide/teleport',
'/guide/render-function',
'/guide/plugins',
'/guide/composition-api-introduction'
Expand All @@ -54,9 +55,7 @@ const sidebar = {
{
title: 'Tooling',
collapsable: false,
children: [
'/guide/single-file-component'
]
children: ['/guide/single-file-component']
},
{
title: 'Scaling Up',
Expand All @@ -71,9 +70,7 @@ const sidebar = {
{
title: 'Tooling',
collapsable: false,
children: [
'/guide/testing'
]
children: ['/guide/testing']
},
{
title: 'Migration to Vue 3',
Expand Down
29 changes: 29 additions & 0 deletions src/api/built-in-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,32 @@
For detailed usage, see the guide section linked below.

- **See also:** [Content Distribution with Slots](../guide/component-basics.html#content-distribution-with-slots)

## teleport

- **Props:**

- `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

```html
<!-- ok -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />

<!-- Wrong -->
<teleport to="h1" />
<teleport to="some-string" />
```

- `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.

```html
<teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</teleport>
```

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.

- **See also:** [Teleport component](../guide/teleport.html#teleport)
104 changes: 104 additions & 0 deletions src/guide/teleport.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Teleport

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.

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"`

```html
<body>
<div id="app" class="demo">
<h3>Move the #content with the portal component</h3>
<div>
<p id="content">
This should be moved to #endofbody.
</p>
<span>This content should be nested</span>
</div>
</div>
<div id="endofbody"></div>
</body>
```

To do so, we can use Vue's built-in `<teleport>` component:

```html
<body>
<div id="app" class="demo">
<h3>Move the #content with the portal component</h3>
<div>
<teleport to="#endofbody">
<p id="content">
This should be moved to #endofbody.
</p>
</teleport>
<span>This content should be nested</span>
</div>
</div>
<div id="endofbody"></div>
</body>
```

As a result, we will have `teleport` content moved in the rendered DOM tree:

<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">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/WNrXYXd">
Teleport</a> by Vue (<a href="https://codepen.io/Vue">@Vue</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

As you can see, all of the children of `<teleport>` will be appended to `<div id="endofbody">`.

## Using with Vue components

If `<teleport>` contains a Vue component, it will remain a logical child component of the `<teleport>`'s parent:

```js
const app = Vue.createApp({
template: `
<h1>Root instance</h1>
<parent-component />
`
})

app.component('parent-component', {
template: `
<h2>This is a parent component</h2>
<teleport to="#endofbody">
<child-component name="John" />
</teleport>
`
})

app.component('child-component', {
props: ['name'],
template: `
<div>Hello, {{ name }}</div>
`
})
```

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.

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.

## Using multiple teleports on the same target

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.

```html
<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>

<!-- result-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>
```

You can check `<teleport>` component options in the [API reference](../api/built-in-components.html#teleport)