Files
inkreach-official-website/apps/website/.agents/skills/vue-debug-guides/reference/teleport-target-must-exist.md
T
yeuimu 6c61a4e871 feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma
  binaryTargets for openssl 3.0
- nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal
  cron, http->https redirect
- prisma: add origin_goods.delisted migration, sync missing schema
  (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz
- api: CORS wildcard reflection, helmet CORP cross-origin, price
  backfill in persistProductDetail, categoryIcon ancestor fallback,
  mediaByColor per-color gallery in public goods detail
- admin: /admin base path (vite + router)
- import-data.mjs: udt_name casting, serial sequence advance fix
2026-08-26 14:23:09 +08:00

3.3 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Teleport Target Must Exist Before Mount HIGH Teleport will fail silently or throw errors if target element doesn't exist when component mounts gotcha
vue3
teleport
modal
dom
lifecycle

Teleport Target Must Exist Before Mount

Impact: HIGH - The teleport to target must already exist in the DOM when the <Teleport> component is mounted. If the target doesn't exist, Vue will throw an error and the teleported content won't render.

This is a common source of bugs when using modals, tooltips, or other teleported UI elements, especially when targeting Vue-rendered elements.

Task Checklist

  • Ensure teleport target exists in the DOM before <Teleport> mounts
  • Place teleport containers (e.g., #modals, #tooltips) in index.html outside the Vue app
  • If targeting Vue-rendered elements, ensure they mount before the Teleport
  • Use Vue 3.5+ defer prop when target is rendered later in the same component tree

Incorrect:

<template>
  <!-- ERROR: Target doesn't exist yet when Teleport mounts -->
  <Teleport to="#modal-container">
    <div class="modal">Modal content</div>
  </Teleport>

  <!-- Target is defined after the Teleport -->
  <div id="modal-container"></div>
</template>

Correct - Option 1: External container in index.html:

<!-- index.html -->
<body>
  <div id="app"></div>
  <!-- Container exists before Vue app mounts -->
  <div id="modals"></div>
  <div id="tooltips"></div>
</body>
<template>
  <!-- Safe: #modals exists before any Vue component mounts -->
  <Teleport to="#modals">
    <div v-if="showModal" class="modal">Modal content</div>
  </Teleport>
</template>

Correct - Option 2: Teleport to body:

<template>
  <!-- Safe: body always exists -->
  <Teleport to="body">
    <div v-if="showModal" class="modal">Modal content</div>
  </Teleport>
</template>

Correct - Option 3: Vue 3.5+ defer prop:

<template>
  <!-- Works in Vue 3.5+: defer resolves target after other parts mount -->
  <Teleport defer to="#late-container">
    <div class="modal">Modal content</div>
  </Teleport>

  <!-- Target rendered later in template -->
  <div id="late-container"></div>
</template>

Defer Prop Limitations (Vue 3.5+)

The defer prop only waits for elements rendered in the same mount/update tick:

<template>
  <!-- ERROR: defer won't help if target mounts asynchronously -->
  <Teleport defer to="#async-container">
    <div>Content</div>
  </Teleport>

  <!-- If this component loads asynchronously, defer won't work -->
  <Suspense>
    <AsyncComponent />  <!-- Contains #async-container -->
  </Suspense>
</template>

Common Patterns

<!-- index.html -->
<body>
  <div id="app"></div>

  <!-- Teleport destinations outside Vue app -->
  <div id="modals" aria-live="polite"></div>
  <div id="notifications" aria-live="assertive"></div>
  <div id="tooltips"></div>
</body>

Reference