Teleport is by far one of my favorite additions to Vue 3. It is not specifically a Composition API feature. It means that we can use it even with the Options API if you’re using Vue 3. Teleport allows a part of a component to travel to any node of the DOM tree. That means if we have a component heavily nested inside somewhere like html > body > main > layout > container > modal, we can easily port this modal to somewhere like the body element directly. The modal can still maintain its states from inside the child component where it belongs!
This is usually useful in the case of modals and notifications, where we’re forced to move out the modal somewhere outside the child components for it to behave correctly.
For instance, let’s say we have a page full of notifications. We can see the latest notification by clicking on a button. This notification has to appear on top of all the elements, absolutely placed. We can decide whether to hide or show the notification using a reactive state from the child component. However, the actual notification element is created somewhere else.
Here’s our index.html file:
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Notifications App</title>
</head>
<body>
<div id="app"></div>
<div class="notifications-container"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
You’d notice that we have used a class named notifications-container at line 13. This is where we target to teleport the actual notification element.
Here’s some CSS for styling the elements:
//base.css
.notification {
background: lavender;
padding: 10px 20px;
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 80%;
height: auto;
z-index: 1;
box-shadow: 10px 10px #cacad7;
}
.notifications-container {
position: initial;
}
Code language: PHP (php)
And finally, here’s our notification / modal component:
//notifications.vue
<script setup>
import { reactive } from 'vue'
const notificationVisibility = reactive({
showNotification: false
})
const toggleNotification = () => {
notificationVisibility.showNotification = !notificationVisibility.showNotification
}
</script>
<template>
<div>
<h2>Notifications</h2>
<ul>
<li>Dummy notification 1</li>
<li>Dummy notification 2</li>
<li>Dummy notification 3</li>
<li>Dummy notification 4</li>
</ul>
<button @click="toggleNotification">Show latest notification</button>
<teleport to=".notifications-container">
<div v-if="notificationVisibility.showNotification" class="notification">
<h2>This is a notification</h2>
<p>Modal example by www.nightprogrammer.com. Lorem ipsum dolor sit amet consectetur adipisicing elit. Beatae ipsa laboriosam vero natus ut rerum quaerat, saepe praesentium tempore et hic velit odio nemo minus labore quam ullam quod architecto?</p>
<button @click="toggleNotification">Hide notification</button>
</div>
</teleport>
</div>
</template>
Code language: HTML, XML (xml)
In the above file, we’re using teleport on line 22. We have teleoprted it to the class notifications-container. Of course, we can target by any identifier, class, or even tag name like body. We have also used a reactive state named notificationVisibility.showNotification. We have then created a method named toggleNotification to toggle its visibility.
Here’s what the above code would look like in action: