Getting Started with Portal-Vue
What is PortalVue?
PortalVue is a set of two components that allow you to render a component's template (or a part of it) anywhere in the document - even outside the part controlled by your Vue App!
What about Vue 3's Teleport
?
Good question! For most scenario's, you might not even need portal-vue
, since the new Teleport
component does it better than this library does (read: Without the caveats).
For an in-depth explanation, look here
Setup
Install Package:
npm install --save portal-vue@next
# or with yarn
yarn add portal-vue@next
Add it to your application:
import PortalVue from 'portal-vue'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.use(PortalVue)
app.mount('#app')
For more detailed installation instructions, additional options and installation via CDN, see the Installation section of the documentation.
Browser Support
This project is build for modern Javascript, sind Vue itself also targets modern browsers. It supports all browsers that also support ES Modules - those are:
- Chrome >=61
- Firefox >=60
- Safari >=11
- Edge >=16
If you need to support older browsers for some reason, make sure to include node_modules/portal-vue/dist
in the list of files that you transpile with babel.
Vue CLI offers a dedicated option for this with transpileDependencies
// vue.config.js
module.exports = {
transpileDependencies: ['portal-vue']
}
Usage
About the examples
The following examples contain live demos. When looking at them, keep in mind that for demo purposes, we move content around within one component, however in reality the <portal-target>
can be positioned anywhere in your App.
Also, the code of the Examples uses the Single-File-Component Format (".vue
" files). If you're not familiar with this, check out the official docs here.
The Basics
<portal to="destination">
<p>This slot content will be rendered wherever the
<portal-target> with name 'destination'
is located.
</p>
</portal>
<portal-target name="destination">
<!--
This component can be located anywhere in your App.
The slot content of the above portal component will be rendered here.
-->
</portal-target>
Enabling/Disabling the Portal
<portal to="destination" :disabled="true">
<p>
This slot content will be rendered right here as long as the `disabled` prop
evaluates to `true`,<br />
and will be rendered at the defined destination as when it is set to `false`
(which is the default).
</p>
</portal>
Conditional rendering with v-if
<portal to="destination" v-if="usePortal">
<ul>
<li>
When 'usePortal' evaluates to 'true', the portal's slot content will be
rendered at the destination.
</li>
<li>
When it evaluates to 'false', the content will be removed from the
destination
</li>
</ul>
</portal>
Multiple Portals, one Target
The PortalTarget
component has a multiple
mode, which allows to render content from multiple Portal
components at the same time.
The order the content is rendered in can be adjusted through the order
prop on the Portal
components:
<portal to="destination" :order="2">
<p>some content</p>
</portal>
<portal to="destination" :order="1">
<p>some other content</p>
</portal>
<div class="some-wrapper">
<portal-target name="destination" multiple />
</div>
Result
<div class="some-wrapper">
<p>some other content</p>
<p>some content</p>
</div>
Use Cases
Positioning Modals & Overlays
In older browsers, position: fixed
works unreliably when the element with that property is nested in a node tree that has other position
values.
But we normally need it to render components like modals, dialogs, notifications, snackbars and similar UI elements in a fixed position.
Also, z-indices can be a problem when trying to render things on top of each other somewhere in the DOM.
With PortalVue, you can render your modal/overlay/dropdown component to a <portal-target>
that you can position as the very last in the page's body
, making styling and positioning much easier and less error-prone.
Now you can position your components with position: absolute
instead
<body>
<div id="app" style="position: relative;">
<div>
<portal to="notification-outlet">
<notification style="position: absolute; top: 20px; right: 20px;">
This overlay can be positioned absolutely very easily.
</notification>
</portal>
</div>
<!-- rest of your app -->
</div>
<portal-target name="notification-outlet"></portal-target>
</body>
Rendering dynamic widgets
If you use Vue for small bits and pieces on your website, but want to render something in a location at the other end of the page, PortalVue got you covered.
Tell us about your use case!
We're sure you will find use cases beyond the ones we mentioned. If you do, please let us know by opening an issue on Github and we will include it here.