codejump

AcademyVue

Teleport & Suspense

Teleport moves a component's DOM without moving its logical position; Suspense gives an async component a fallback while it loads.

2 min readUpdated

3 exercises

Waiting at the end of this page.

Logical position and DOM position are usually the same thing — Teleport separates them

A component's markup normally renders exactly where it is written in the parent's template. <Teleport> breaks that assumption on purpose:

vue
<template>
  <div class="card" style="overflow: hidden">
    <Teleport to="body">
      <div v-if="open" class="modal">Modal content</div>
    </Teleport>
  </div>
</template>

The modal's reactive state, its lifecycle, its position in the component tree — all of that stays exactly where it is written, inside .card. Only its rendered DOM moves, to a direct child of <body>. This is the fix for the entire class of bug where a modal, tooltip or dropdown gets visually clipped by a parent's overflow: hidden, trapped under a lower z-index, or squeezed by a parent's fixed dimensions — moving the DOM sidesteps every one of those constraints without moving the component's actual identity.

defineAsyncComponent works standalone; Suspense adds a fallback

JavaScript
const UserPanel = defineAsyncComponent(() => import('./UserPanel.vue'))

This alone is a complete, working async component: Vue renders nothing in its place until the import resolves, then swaps it in. No <Suspense> required for it to function. What <Suspense> adds is a coordinated point to show something better than nothing during that gap:

vue
<template>
  <Suspense>
    <template #default>
      <UserPanel />
    </template>
    <template #fallback>
      <p>Loading…</p>
    </template>
  </Suspense>
</template>

Without the <Suspense> wrapper, the spot where UserPanel will eventually appear is simply empty in the meantime — not broken, just silent. <Suspense>'s #fallback slot is what fills that silence.

Suspense coordinates every async dependency underneath it, not just one

Nest several async components inside one <Suspense> and its #fallback stays visible until all of them have resolved, then swaps to #default once. This is the actual reason to reach for <Suspense> over rolling a loading flag by hand per component: coordinating "show the fallback until everything below me is ready" across an arbitrary, changing set of async children is exactly the kind of bookkeeping that gets error-prone to hand-write and free once <Suspense> owns it.

What interviewers check

Whether Teleport gets framed as a DOM-position tool, not a "modal component" — the same mechanism moves a tooltip, a toast, or a dropdown menu out of an overflow: hidden ancestor, and naming the general mechanism (not just "the modal pattern") is what separates memorized syntax from an actual understanding of what <Teleport> does.

Now practice it

1 quiz · 2 drills

Reading this page is the cheap half. These are the exercises that make you use it.