Skip to content
← Todas las preguntas
⚡ Intermedio

¿Qué son Teleport, Fragments y Suspense?

🧩 Componentes⏳ Suspense🌀 Teleport

Estas son tres funcionalidades integradas introducidas en Vue 3. Cada una resuelve un problema diferente: renderizar contenido fuera del árbol de componentes, permitir múltiples elementos raíz, y manejar dependencias asíncronas con estados de carga.

Teleport

<Teleport> renderiza sus hijos en una parte diferente del DOM, fuera del elemento del componente padre. La lógica del componente (props, eventos, reactividad) permanece en su lugar; solo la salida DOM se mueve.

vue
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>

<template>
  <button @click="showModal = true">Abrir</button>

  <Teleport to="body">
    <div v-if="showModal" class="modal-overlay">
      <div class="modal">
        <p>Esto se renderiza como hijo directo de body</p>
        <button @click="showModal = false">Cerrar</button>
      </div>
    </div>
  </Teleport>
</template>
Open in Vue Playground

Sin Teleport, un modal dentro de un componente profundamente anidado hereda todo el CSS del padre (overflow: hidden, z-index, transform), lo cual puede recortar o posicionar mal el modal. Teleportar a <body> evita esos problemas. La prop to acepta cualquier selector CSS o elemento DOM.

Usos comunes: modales, tooltips, menús dropdown, notificaciones. Cualquier cosa que necesite escapar visualmente del layout de su padre.

Fragments

En Vue 2, cada componente necesitaba un único elemento raíz. Esto forzaba <div> wrapper innecesarios:

vue
<!-- Vue 2: requería un único raíz -->
<template>
  <div>
    <header>Header</header>
    <main>Content</main>
  </div>
</template>
Open in Vue Playground

Vue 3 soporta fragments, es decir, múltiples elementos raíz sin wrapper:

vue
<!-- Vue 3: múltiples raíces, sin wrapper necesario -->
<template>
  <header>Header</header>
  <main>Content</main>
  <footer>Footer</footer>
</template>
Open in Vue Playground

Un detalle: los atributos fallthrough no funcionan automáticamente con componentes multi-raíz porque Vue no sabe a qué raíz aplicarlos. Necesitas vincular $attrs explícitamente.

Suspense

<Suspense> muestra contenido fallback mientras espera a que los componentes hijos asíncronos se resuelvan. Funciona con componentes que tienen un async setup() o que se cargan con defineAsyncComponent.

vue
<template>
  <Suspense>
    <template #default>
      <UserDashboard />
    </template>
    <template #fallback>
      <LoadingSpinner />
    </template>
  </Suspense>
</template>
Open in Vue Playground

Si UserDashboard tiene un setup asíncrono (devuelve una promise), Suspense muestra LoadingSpinner hasta que la promise se resuelve. También puedes manejar errores con onErrorCaptured en el padre.

Nota: Suspense sigue siendo una API experimental. El comportamiento base es estable, pero la API puede tener cambios menores.

Ver también: ¿Cómo funciona Suspense para componentes asíncronos? · ¿Qué son los componentes asíncronos? · ¿Qué son los atributos fallthrough?

Referencias

Publicado bajo la licencia MIT.