Vue Safe Teleport
vue-safe-teleport is a utility package for Vue 3 applications that enhances the built-in `<Teleport>` component to prevent common runtime errors related to target availability. It provides `<SafeTeleport>` and `<TeleportTarget>` components, ensuring that content is only teleported once its designated target DOM element is fully mounted and available. The current stable version is `0.1.2`. While the package is relatively new, its recent bug fixes (e.g., v0.1.2 for import extensions) indicate active maintenance. Key differentiators include its explicit `TeleportTarget` component for robust target registration and a fallback single-frame delay when using `SafeTeleport` with a standard DOM selector, directly addressing the "Failed to locate Teleport target with selector" issue that frequently arises from race conditions in component lifecycles. It aims to be a drop-in replacement for `<Teleport>` with added safety.
Common errors
-
Failed to locate Teleport target with selector "#my-target"
cause Vue's native Teleport attempts to render content into a target DOM element that has not yet been mounted or is dynamically added later in the component lifecycle, leading to a race condition.fixReplace Vue's `<Teleport>` with `<SafeTeleport>` from `vue-safe-teleport` and ensure a `<TeleportTarget id="my-target" />` component exists and is rendered before `<SafeTeleport>` attempts to mount its content. -
Module not found: Error: Can't resolve 'vue-safe-teleport'
cause Incorrect import path or module resolution issues, potentially due to missing file extensions in imports in older versions or incorrect CJS/ESM interop.fixVerify the package is correctly installed (`pnpm i vue-safe-teleport`). Ensure you are using ESM `import` statements (e.g., `import { SafeTeleport } from 'vue-safe-teleport'`) and update to `vue-safe-teleport@0.1.2` or later to leverage import path fixes. -
Property 'SafeTeleport' does not exist on type 'typeof import("vue-safe-teleport")' or 'Component is not defined'.cause Attempting to use `SafeTeleport` or `TeleportTarget` without explicitly importing them as named exports, or without installing the `VueSafeTeleport` plugin globally if not importing them directly.fixFor direct component usage, ensure `import { SafeTeleport, TeleportTarget } from 'vue-safe-teleport'` is present. If using the plugin, ensure `app.use(VueSafeTeleport)` is called, which registers them globally.
Warnings
- gotcha When migrating from Vue's native `<Teleport>`, you must replace `<Teleport>` with `<SafeTeleport>`. While props are largely compatible, the underlying behavior for target resolution changes significantly.
- gotcha Using `<SafeTeleport>` without a corresponding `<TeleportTarget>` will still resolve the target, but it will implicitly wait one frame if the target is not immediately available. This introduces a slight delay and might not be suitable for performance-critical scenarios where immediate rendering is expected.
- breaking The `v0.1.2` release included a fix for `add extensions to imports`. While intended as a bug fix, users on older versions (pre-0.1.2) in strict module environments or specific build setups might encounter module resolution errors when importing components or the plugin.
Install
-
npm install vue-safe-teleport -
yarn add vue-safe-teleport -
pnpm add vue-safe-teleport
Imports
- VueSafeTeleport
const VueSafeTeleport = require('vue-safe-teleport')import VueSafeTeleport from 'vue-safe-teleport'
- SafeTeleport
import SafeTeleport from 'vue-safe-teleport'
import { SafeTeleport } from 'vue-safe-teleport' - TeleportTarget
import { TeleportTarget } from 'vue-safe-teleport'
Quickstart
// main.js or similar
import { createApp } from 'vue';
import App from './App.vue';
import VueSafeTeleport from 'vue-safe-teleport';
const app = createApp(App);
app.use(VueSafeTeleport);
app.mount('#app');
// App.vue or another component
<template>
<div>
<h1>My Vue App</h1>
<!-- Define a dedicated teleport target -->
<TeleportTarget id="modals" />
<button @click="showModal = true">Open Safe Teleported Modal</button>
<!-- Content to be safely teleported to #modals -->
<SafeTeleport to="#modals" v-if="showModal">
<div style="background: white; border: 1px solid #ccc; padding: 20px; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1000;">
<h2>Modal Content</h2>
<p>This content is teleported securely.</p>
<button @click="showModal = false">Close</button>
</div>
</SafeTeleport>
<!-- Example without TeleportTarget, waits one frame -->
<SafeTeleport to="#floating-element">
<div style="position: absolute; bottom: 10px; right: 10px; background: lightblue; padding: 5px;">
Floating Message
</div>
</SafeTeleport>
<div id="floating-element" style="position: relative; width: 100px; height: 100px;"></div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { SafeTeleport, TeleportTarget } from 'vue-safe-teleport';
const showModal = ref(false);
</script>
<style>
/* Basic styling for demo */
body { margin: 0; font-family: sans-serif; }
#app { padding: 20px; }
</style>