Vue Teleport
Teleport is a built-in component that can "teleport" a part of a component's internal template to a DOM node outside of the component's DOM structure. This is very useful for handling content that needs to be visually detached from the component hierarchy but logically still belongs to that component.
The most common use cases are creating modals, notifications, or tooltips.
Problem Scenario
Suppose you're developing a modal component. Ideally, the modal's button (trigger) and the modal itself should be encapsulated in the same component. However, the modal's DOM structure usually needs to be rendered as a direct child node of the <body> element to avoid being affected by the parent component's z-index or overflow styles.
<!-- MyModal.vue -->
<template>
<button @click="open = true">Open Modal</button>
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</template>
<style>
.modal {
position: fixed;
z-index: 999;
top: 20%;
left: 50%;
width: 300px;
margin-left: -150px;
}
</style>If this <MyModal> component is nested inside a container with overflow: hidden or z-index, the modal's positioning and display will have issues.
Using <Teleport>
<Teleport> provides a simple way to solve this problem. We can use it to wrap the modal's HTML and specify a "teleport" target.
<Teleport> accepts a to prop, which should be a CSS selector string or an actual DOM node.
<!-- MyModal.vue with Teleport -->
<template>
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
</template>Now, no matter where you use the <MyModal> component, its modal part will be rendered as a child element of <body>, thereby avoiding CSS stacking context issues.
Importantly, even though the DOM position has changed, the content inside Teleport is still a logical child component of <MyModal>. This means:
- It can still access the
dataandpropsof the<MyModal>component (such as theopenstate). - It can still receive
emitevents from the<MyModal>component.
Using with Components
<Teleport> can not only teleport native DOM elements but also components.
<Teleport to="#modals">
<MyModalComponent :is-open="showModal" @close="showModal = false" />
</Teleport>Disabling Teleport
In some cases, we might need to conditionally disable Teleport's functionality. For example, on desktop we want the component to be teleported to <body>, but on mobile we want it to stay inside the component. We can achieve this through the disabled prop.
<Teleport to="body" :disabled="isMobile">
<!-- content -->
</Teleport>Teleport provides a clean way to manage UI fragments that need to "break out" of the DOM structure while maintaining their logical parent-child relationships, making it a powerful tool for building complex UIs.