Skip to main content
Practice Problems

Teleport in Vue.js

What is Teleport?

Teleport is a built-in Vue 3 component that allows rendering content anywhere in the DOM, even outside the Vue app root element.

This is especially useful for modals, tooltips, notifications, and other elements that should be outside the current hierarchy.


Basic Usage

javascript
<template> <div class="component"> <button @click="showModal = true">Open Modal</button> <Teleport to="body"> <div v-if="showModal" class="modal"> <p>I'm rendered in body!</p> <button @click="showModal = false">Close</button> </div> </Teleport> </div> </template> <script setup> import { ref } from 'vue' const showModal = ref(false) </script> <style scoped> .modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; z-index: 1000; } </style>

The <Teleport> content will be rendered in <body>, not inside .component.


Selectors for to

The to attribute accepts CSS selector or DOM element:

CSS Selector

javascript
<!-- By ID --> <Teleport to="#modal-container"> <div>Content</div> </Teleport> <!-- By class --> <Teleport to=".modal-wrapper"> <div>Content</div> </Teleport> <!-- By tag --> <Teleport to="body"> <div>Content</div> </Teleport>

DOM Element

javascript
<script setup> import { ref, onMounted } from 'vue' const targetElement = ref(null) onMounted(() => { targetElement.value = document.getElementById('custom-container') }) </script> <template> <Teleport :to="targetElement" v-if="targetElement"> <div>Content</div> </Teleport> </template>

Disabling Teleport

You can dynamically enable/disable teleportation:

javascript
<template> <Teleport to="body" :disabled="!isMobile"> <div class="modal"> On mobile - in body, on desktop - here </div> </Teleport> </template> <script setup> import { ref, onMounted } from 'vue' const isMobile = ref(false) onMounted(() => { isMobile.value = window.innerWidth < 768 }) </script>

Multiple Teleports to One Target

You can teleport multiple components to one place:

javascript
<!-- Component1.vue --> <Teleport to="#notifications"> <div>Notification 1</div> </Teleport> <!-- Component2.vue --> <Teleport to="#notifications"> <div>Notification 2</div> </Teleport>
html
<!-- index.html --> <div id="app"></div> <div id="notifications"></div>

Both notifications will render in #notifications in mount order.


Practical Examples

javascript
<!-- Modal.vue --> <template> <Teleport to="body"> <Transition name="modal"> <div v-if="isOpen" class="modal-overlay" @click="close"> <div class="modal-content" @click.stop> <button class="modal-close" @click="close">×</button> <slot /> </div> </div> </Transition> </Teleport> </template> <script setup> defineProps({ isOpen: Boolean }) const emit = defineEmits(['close']) function close() { emit('close') } </script> <style scoped> .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; } .modal-content { background: white; padding: 20px; border-radius: 8px; max-width: 500px; position: relative; } .modal-close { position: absolute; top: 10px; right: 10px; background: none; border: none; font-size: 24px; cursor: pointer; } </style>

Usage:

javascript
<template> <button @click="isModalOpen = true">Open</button> <Modal :is-open="isModalOpen" @close="isModalOpen = false"> <h2>Title</h2> <p>Modal content</p> </Modal> </template> <script setup> import { ref } from 'vue' import Modal from './Modal.vue' const isModalOpen = ref(false) </script>

Teleport vs CSS position: fixed

Without Teleport

javascript
<template> <div class="parent" style="position: relative; overflow: hidden"> <div class="modal" style="position: fixed"> <!-- May be cut off due to overflow: hidden --> </div> </div> </template>

Problems:

  • May be cut off by parent overflow
  • Inherits z-index context
  • Difficult to manage stacking order

With Teleport

javascript
<template> <div class="parent" style="position: relative; overflow: hidden"> <Teleport to="body"> <div class="modal" style="position: fixed"> <!-- Always displays correctly --> </div> </Teleport> </div> </template>

Advantages:

  • Independent of parent styles
  • Own stacking context
  • Easy to manage z-index

Limitations

Target element must exist

javascript
<!-- Wrong --> <Teleport to="#non-existent"> <div>Error!</div> </Teleport> <!-- Correct --> <Teleport to="body"> <div>Works!</div> </Teleport>

Teleport doesn't change logical hierarchy

javascript
<script setup> import { provide } from 'vue' provide('theme', 'dark') </script> <template> <Teleport to="body"> <!-- inject still works! --> <ChildComponent /> </Teleport> </template>

Props, events, provide/inject continue to work, as only DOM changes, not component hierarchy.


Conclusion

Teleport:

  • Renders content anywhere in DOM
  • Doesn't change logical component hierarchy
  • Useful for modals, tooltips, notifications
  • Solves overflow and z-index problems
  • Can be disabled dynamically
  • Supports multiple teleports to one target

In interviews:

Important to be able to:

  • Explain what Teleport is and why it's needed
  • Show usage examples (modals, notifications)
  • Describe problems Teleport solves
  • Explain that logical hierarchy doesn't change
  • Give differences from CSS position: fixed

Content

What is Teleport?Basic UsageSelectors for toCSS SelectorDOM ElementDisabling TeleportMultiple Teleports to One TargetPractical ExamplesModal WindowTeleport vs CSS position: fixedWithout TeleportWith TeleportLimitationsTarget element must existTeleport doesn't change logical hierarchyConclusion

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems