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
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:
<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
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:
<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 drillsReading this page is the cheap half. These are the exercises that make you use it.
- TeleportProA modal trapped inside a 50px clipped container — escapes to document.body instead of inheriting the overflow.DrillSolve · HardDrillSolve · Hard
- SuspenseProAn async component with no fallback at all while pending — a manually-resolvable promise makes the gap testable.DrillSolve · HardDrillSolve · Hard
- Performance · Bundle OptimizationAsync boundaries and code-splitting are squarely bundle-optimization territory — this set connects the two.QuizTake · HardQuizTake · Hard
Read next
Performance Patterns: KeepAlive & v-memo
KeepAlive caches a component instance instead of destroying it; v-memo skips a re-render entirely when nothing it depends on changed.
2 min
Compound Components
Tabs, Tab and TabPanel coordinate through one shared provide/inject context — each part only has to talk to that context, never to its siblings.
2 min