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
String
value: 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
1.1.0+
Default slotAny 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
2.0.0+
Default scoped slotIf 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
1.1.0+
Events APIchange
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.