PortalTarget
This component is an outlet for any content that was sent by a <Portal> component. It renders received content and doesn't do much else.
Example usage
<portal-target name="destination" />
This is an abstract component which means it will not be visible in vue-devtools
Props API
multiple 1.2.0+
When multiple is true, the portal will be able to receive and render content from multiple <Portal> component at the same time.
You should use the order prop on the <Portal> to define the order in which the contents should be rendered:
Source
<portal to="destination" :order="2">
<p>some content</p>
</portal>
<portal to="destination" :order="1">
<p>some other content</p>
</portal>
<portal-target name="destination" multiple />
2
3
4
5
6
7
8
Result
<div class="vue-portal-target">
<p>some other content</p>
<p>some content</p>
</div>
2
3
4
Usage with `slim`
multiple may not behave as expected when its <PortalTarget> is also in slim mode because slim attempts to
assign the content's root node as the <PortalTarget>'s root node, thereby only rendering the first of all incoming nodes.
name
| Type | Required | Default |
|---|---|---|
String | yes | none |
Defines the name of this portal-target. <Portal> components can send content to this instance by this name.
slim
| Type | Required | Default |
|---|---|---|
Boolean | no | false |
When set to true, the component will check if the sent content has only one root node. If that is the case, the component will not render a root node of its own but instead just return that single node.
Source
<portal to="destination"> <p>Only one content element</p> </portal>
<portal-target name="destination" slim />
2
3
Result
<p>Only one content element</p>
BREAKING CHANGE IN 2.0.0
When there's no content and slim is set, the target doesn't render an empty <div> anymore, it renders nothing (a comment node as a placeholder is rendered, to be precise).
slotProps 1.3.0+
| Type | Required | Default |
|---|---|---|
Object | no | {} |
TIP
This prop is only useful when the PortalTarget received content from a scoped Slot of a <Portal>.
The slotProps object is used as props to render the scoped slot from a <Portal>.
Source
<portal to="destination">
<p slot-scope="props">This scoped slot content is so {{ props.state }}</p>
</portal>
<portal-target name="destination" slot-props="{state: 'cool!'}" />
2
3
4
5
Result
<div class="vue-portal-target">
<p>This scoped slot content is so cool!</p>
</div>
2
3
It has a counterpart of the same name on the <Portal> component to pass props to the slot content when the <Portal> is disabled.
tag
| Type | Required | Default |
|---|---|---|
String | no | 'DIV' |
Defines the type of tag that should be rendered as a root component.
Source
<portal-target name="destination" tag="span" />
Result
<span class="vue-portal-target">
<!-- any content from <Portal> component may be rendered here -->
</span>
2
3
transition changed in 2.0.0+
| Type | Required | Default |
|---|---|---|
Boolean|String|Object | no | none |
This property is used to configure a transition for the portal content. By default, it will render
a <transition-group>, which will respect the <PortalTarget>'s tag property and will render instead of the
plain wrapper element that is usually rendered.
It accepts:
- a
Stringvalue: will render a globally registered component of this name. - a
Component: will render<transition-group>with the object's content passed as props.
Example with string:
<portal-target
name="dest"
slim
transition="fade">
</portal-target>
2
3
4
5
Example with Component:
<portal-target
name="dest" slim
:transition="fadeTransition">
</portal-target>
2
3
4
computed: {
fadeTransition() {
return {
functional: true,
render(h, context) {
return h('transition', { props: { name: 'fade', mode: 'out-in' } }, context.children)
}
}
},
globalTransitionComponent() {
// instead of creating the Transition component locally like above,
// you probably would like to re-use a component, that you registered
// either globally or locally.
return Vue.component('yourGloballyregisteredComponent')
// or
return this.$options.components('yourLocallyregisteredComponent')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Resuable Transition components
The Vue documentation has a section about creating resusable transititions with components
Slim Mode
When slim is also specified, it will render a <transition> instead of a <transition-group>.
transitionEvents removed in 2.0.0
| Type | Required | Default |
|---|---|---|
Object | no | none |
This property requires that the `transition` prop is defined as well.
Accepts an object whose keys match the transition component's events. Each key's value should be a callback function for the transition.
<portal-target
name="dest"
transition="fade"
:transition-events="{ enter: handleEnter, leave: handleLeave }"
></portal-target>
2
3
4
5
Slots API
Default slot 1.1.0+
Any existing slot content is rendered in case that no content from any source Portal is available.
Example:
Source
<portal-target name="destination" tag="span">
<p>This is rendered when no other content is available.</p>
</portal-target>
2
3
Result
<span class="vue-portal-target">
<p>This is rendered when no other content is available.</p>
</span>
2
3
Default scoped slot 2.0.0+
If a scoped slot is provided, its content is rendered in case that no content from any source Portal is available. The scoped slot receives the slotProps prop as its argument.
Example:
Source
<portal-target name="destination" :slotScope="{ message: 'Hi!' }">
<p slot-scope="props">
{{props.message}} This is rendered when no other content is available.
</p>
</portal-target>
2
3
4
5
Result
<div class="vue-portal-target">
<p>This is rendered when no other content is available.</p>
</div>
2
3
Events API 1.1.0+
change
Emitted everytime the component re-renders because the content from the <Portal> changed.
It receives two arguments, each is a Boolean, indicating the absense or presence of content for the target.
<template>
<portal-target name="destination" @change="handleUpdate" />
</template>
<script>
export default {
methods: {
handleUpdate(newContent, oldContent) {
// do something with the info.
},
},
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
BREAKING CHANGE in 2.0.0
The event now is simple Boolean values, indicating wether the target is/was empty or not.
Previously, we emitted the old and new contents, but that code was too cumbersome for little value.