¿Sabías que puedes mover parte del DOM de un componente Vue a otro lugar del HTML sin romper la reactividad? En esta guía aprenderás cómo usar <Teleport> en Vue 3, desde lo básico hasta casos reales como notificaciones, menús contextuales y overlays.
)
<Teleport>?<Teleport> es un componente integrado de Vue 3 que te permite renderizar una parte del DOM de tu componente en otro lugar del documento HTML, sin romper la lógica del componente ni su reactividad.
Imagina que tienes un modal, una notificación, o un menú que visualmente necesita estar en el <body> o en un contenedor global, pero lógicamente pertenece a un componente específico. Aquí es donde entra <Teleport>.
<Teleport>? – La forma básicaLa estructura es muy simple:
<script setup lang="ts"></script>
<template>
<Teleport to="body">
<!-- contenido que será movido al <body> -->
</Teleport>
</template>El prop to acepta un selector CSS o un nodo del DOM.
Todo lo que esté dentro del <Teleport> se renderiza en ese destino.
Se mantiene el contexto del componente padre: props, eventos e inyección siguen funcionando igual.
Estructura base:
<!-- index.html -->
<div id="app"></div>
<div id="notifications"></div>Componente NotificationManager.vue
<script setup lang="ts">
import { ref } from 'vue'
const notes = ref([])
function addNotification(text) {
notes.value.push({ id: Date.now(), text })
setTimeout(() => notes.value.shift(), 3000)
}
defineExpose({ addNotification }) // permite usarlo desde refs
</script>
<template>
<Teleport to="#notifications">
<div v-for="n in notes" class="note">{{ n }}</div>
</Teleport>
</template>Uso en otro componente:
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import NotificationManager from './NotificationManager.vue'
const notifRef = useTemplateRef('notifRef')
function handleAction() {
notifRef.value?.addNotification('¡Acción exitosa!')
}
</script>
<template>
<NotificationManager ref="notifRef" />
<button @click="handleAction">Guardar</button>
</template>disabled:Puedes condicionar el teleport para ciertos dispositivos (ej. overlay en desktop, inline en mobile):
<script setup lang="ts">
import { useMediaQuery } from '@vueuse/core'
// Define isMobile usando media query reactiva
const isMobile = useMediaQuery('(max-width: 768px)')
</script>
<template>
<Teleport :disabled="isMobile" to="body">
<div class="tooltip">Ayuda</div>
</Teleport>
</template>useMediaQuery('(max-width: 768px)') retorna un ref<boolean> reactivo que se actualiza automáticamente cuando cambia el tamaño de la pantalla
Si isMobile.value === true (pantallas menores a 768px), <Teleport> se desactiva y el tooltip se muestra inline en el flujo del componente.
Si isMobile.value === false, el tooltip se teletransporta al <body>, ideal para overlays en escritorio.
<Teleport> se adapta automáticamente sin recarga ni lógica adicional.
El destino (to) debe existir en el DOM cuando el <Teleport> se monta.
Si el destino no está disponible aún, usa defer.
No afecta el árbol de componentes en Vue: los componentes teletransportados siguen siendo hijos del componente que los contiene.
Puedes usar <Transition> dentro del <Teleport> para animaciones fluidas.
<script setup lang="ts">
</script>
<template>
<Teleport to="body">
<Transition name="fade">
<div class="modal">...</div>
</Transition>
</Teleport>
</template><Teleport> es una herramienta poderosa para separar la lógica de tus componentes del posicionamiento en el DOM. Con to, disabled y defer, puedes adaptarlo a múltiples escenarios, desde modales simples hasta comportamientos complejos y contextuales.