Wait for Async Setup Before Rendering
Suspense
`<Suspense>` lets a child component await async work in setup and shows a fallback meanwhile — no manual loading flags.
What you'll learn
- Make a component's setup async
- Wrap with `<Suspense>` and provide a
- Combine with async components for lazy loading
<Suspense> is Vue’s built-in boundary for async components. The child can await data in its setup, and Suspense renders a fallback until the promise resolves.
Async setup
A <script setup> block with a top-level await makes the whole component async.
<!-- UserCard.vue -->
<script setup lang="ts">
const res = await fetch(`/api/me`)
const user = await res.json()
</script>
<template>
<p>Hello {{ user.name }}</p>
</template> Wrap With Suspense
<!-- Parent.vue -->
<template>
<Suspense>
<template #default>
<UserCard />
</template>
<template #fallback>
<p>Loading…</p>
</template>
</Suspense>
</template> While the child’s setup is pending, the #fallback slot renders. Once the promise resolves, Suspense swaps to #default.
Lifecycle Hooks
Suspense emits resolve, pending, and fallback events you can listen to:
<Suspense @resolve="onLoaded" @pending="onPending">…</Suspense> Async Components
<Suspense> also pairs with defineAsyncComponent for code-split components.
import { defineAsyncComponent } from 'vue'
const Heavy = defineAsyncComponent(() => import('./Heavy.vue')) The fallback shows during the chunk download too — one boundary, two use cases.
Error Handling →