{#await}
{#await} blocks render different markup depending on whether a promise is pending, resolved, or rejected. Loading / data / error in one declarative shape — no useState dance.
Three states + race-safe loading
EXAMPLE
<script>
import { onMount } from 'svelte';
let id = 1;
$: user = fetchUser(id); // re-fetch whenever id changes
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(res.statusText);
return res.json();
}
</script>
<!-- 1) Three-state form -->
{#await user}
<p>Loading…</p>
{:then u}
<h1>{u.name}</h1>
<p>{u.email}</p>
{:catch err}
<p class="error">Failed: {err.message}</p>
{/await}
<!-- 2) Skip the pending block (no flicker) — show old data while refetching -->
{#await user then u}
<h1>{u.name}</h1>
{/await}
<!-- 3) Nest inside controls — pagination -->
<button on:click={() => id--} disabled={id === 1}>Prev</button>
<button on:click={() => id++}>Next</button>
<!-- 4) Server-rendered (SvelteKit) — load() in +page.js -->
<!-- +page.js -->
<script context="module">
export async function load({ params, fetch }) {
const res = await fetch(`/api/users/${params.id}`);
return { props: { user: await res.json() } };
}
</script>
<!-- 5) Manual error boundaries — handle in {:catch} -->
{#await fetch('/api/orders').then(r => r.json())}
<Spinner />
{:then orders}
<OrderTable {orders} />
{:catch e}
<ErrorState retry={() => location.reload()} />
{/await}
<!-- 6) Composed with each -->
{#await users}
<Spinner />
{:then list}
{#each list as user (user.id)}
<User {user} />
{/each}
{/await}
Why it matters
{#await user then u} (no pending block) is the secret to UIs that don’t flicker between pages — old content stays until new data arrives.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
{#await promise}
Loading…
{:then value}
Got {value}
{:catch error}
{error.message}
{/await}
Try it Yourself »
Discussion
Loading…