The Problem
Vue's <Teleport> component renders its content at a different location in the DOM. If the target element does not exist when the Teleport component mounts, you get a warning and the content renders inline instead.
Symptoms
- Console warning: "Failed to locate Teleport target"
- Modal or overlay renders in the wrong place
- CSS styles for the target container do not apply
- Teleported content appears inside the component instead of the body
Real Error Message
[Vue warn]: Failed to locate Teleport target with selector "#modal-root"
Note: the target element must exist before the Teleport component is mounted.Common Causes
Cause 1: Target Element Not in index.html
<template>
<Teleport to="#modal-root">
<Modal :open="isOpen">Content</Modal>
</Teleport>
</template>If #modal-root does not exist in index.html, the Teleport fails.
Cause 2: Target Created by Another Component That Has Not Mounted
<!-- App.vue -->
<template>
<Sidebar /> <!-- Creates #sidebar-target -->
<ModalContainer /> <!-- Teleports to #sidebar-target -->
</template>If ModalContainer mounts before Sidebar, the target does not exist yet.
How to Fix It
Fix 1: Add Target to index.html
<!-- index.html -->
<body>
<div id="app"></div>
<div id="modal-root"></div> <!-- Must exist before Vue mounts -->
</body>Fix 2: Use body as Fallback Target
<Teleport to="body">
<Modal :open="isOpen">Content</Modal>
</Teleport>The body element always exists.
Fix 3: Dynamic Target with Validation
```vue <script setup> const target = ref('#modal-root');
onMounted(() => { if (!document.querySelector(target.value)) { console.warn('Teleport target not found, falling back to body'); target.value = 'body'; } }); </script>
<template> <Teleport :to="target"> <Modal :open="isOpen">Content</Modal> </Teleport> </template> ```
Fix 4: Use v-if to Wait for Target
```vue <script setup> const targetReady = ref(false);
onMounted(() => { targetReady.value = !!document.querySelector('#modal-root'); }); </script>
<template> <Teleport v-if="targetReady" to="#modal-root"> <Modal :open="isOpen">Content</Modal> </Teleport> <Modal v-else :open="isOpen">Content</Modal> <!-- Fallback inline render --> </template> ```