Supercharge your Astro app with **automagic lazy-loaded components** powered by HTML streaming. This integration enables you to render fallback placeholders while server-side data is being fetched — even before the page fully loads, and without requiring JavaScript on modern browsers.
-
🚀 Zero JavaScript (Modern Browsers)
Emulates React’sSuspensebehavior—even with JavaScript disabled.- JavaScript is required for smooth exit transitions when using Astro’s View Transitions (
ClientRouter). - JavaScript is required to polyfill behavior on legacy browsers.
- JavaScript is required for smooth exit transitions when using Astro’s View Transitions (
-
🎯 Zero Configuration
Works out of the box with sensible defaults. -
🔧 Customizable Transitions
Configure transition duration and easing for awaited components. -
📦 TypeScript Support
Full type definitions included. -
⚡ Fast Build-Time Performance
Minimal overhead with efficient AST transformations.
-
HTML Streaming must be enabled on the server.
Without streaming, this integration won’t work. -
Astro v4.0.0+ and Node.js v18+
Even though astro-awaited is designed to be intuitive, there are a few important caveats and best practices to keep in mind:
-
⚠️ Works Only with .astro Components Awaited is compatible only with.astrocomponents. You can nest it inside an Astro Island to enable hydration later, but:- The Awaited component itself must remain in a
.astrofile - Do not use the
client:onlydirective, as it disables server-side rendering and breaks HTML streaming
- The Awaited component itself must remain in a
-
🧱 Streaming is top-to-bottom:
Each awaited component blocks the stream until its data is fetched. Structure your layout to avoid bottlenecks. -
⛔ Don’t Fetch in Page Frontmatter:
Fetching data in the page frontmatter blocks the entire page from rendering, including fallbacks. Instead, move fetch logic into individual components to leverage streaming effectively.
Learn more in Astro’s official guide. -
🚫 No HOC (Higher-Order Components):
Astro Awaited relies on HTML streaming and Astro’sslotfeature. Wrapping awaited logic in a separate component will break fallback behavior.
---
// ResultsListAwaited.astro
import { Awaited, Fallback } from 'astro-awaited/components';
import ResultsList from './ResultsList.astro';
---
<Awaited>
<ResultsList query={searchQuery} page={searchPage} />
<Fallback>
<p>Loading...</p>
</Fallback>
</Awaited>---
// index.astro
import ResultsListAwaited from './ResultsListAwaited.astro';
---
<Layout>
<h1>My results list</h1>
<ResultsListAwaited />
</Layout>This won’t work—Astro will treat ResultsListAwaited as an async component and begin fetching before rendering its children.
---
// index.astro
import { Awaited, Fallback } from 'astro-awaited/components';
import ResultsList from './ResultsList.astro';
---
<Layout>
<h1>My results list</h1>
<Awaited>
<ResultsList query={searchQuery} page={searchPage} />
<Fallback>
<p>Loading...</p>
</Fallback>
</Awaited>
</Layout>Use Awaited declaratively, directly in your page layout.
npm install astro-awaited// astro.config.mjs
import { defineConfig } from "astro/config";
import awaited from "astro-awaited";
export default defineConfig({
integrations: [awaited()],
});---
// SearchPage.astro
import { Awaited, Fallback } from 'astro-awaited/components';
import ResultsList from './ResultsList.astro';
---
<Awaited>
<ResultsList query={searchQuery} page={searchPage} />
<Fallback>
<p>Loading...</p>
</Fallback>
</Awaited>The Awaited component provides a graceful fallback mechanism for Astro pages during navigation transitions. It ensures that fallback content is displayed only when the awaited content is not yet ready, and automatically cleans up after route changes.
| Prop | Type | Default | Description |
|---|---|---|---|
transitionDuration |
number |
200 |
Duration (in ms) for the fallback transition animation. |
transitionEase |
"linear" | "ease-in" | "ease-out" | "ease-in-out" |
"linear" |
CSS easing function for the fallback transition. |
contentProps |
HTMLAttributes<'div'> |
undefined |
Props passed directly to the inner content container (data-awaited-content). |
...rest |
HTMLAttributes<'div'> |
— | Any additional props are applied to the outer wrapper (data-awaited-wrapper). |
- Automatic Cleanup: On route transitions, the component removes any lingering awaited content to prevent duplication.
- Fallback Visibility: If the awaited content is empty or not yet rendered, the fallback remains visible. Once content is detected, the fallback fades out smoothly.
- CSS Fallback: If
:has()is unsupported by the browser, the component manually toggles fallback visibility using JavaScript.
The component uses CSS variables for animation control:
--animationDuration: ${transitionDuration}ms;
--animationEase: ${transitionEase};These are applied to the fallback element for smooth transitions.
The <Fallback> component defines the placeholder UI shown while awaited content is loading or unavailable. It’s designed to be slotted into the <Awaited> component using the fallback slot, and it automatically transitions out once the awaited content becomes visible.
<Awaited>
<Fallback>
<div class="spinner" />
</Fallback>
<div>
<!-- Your awaited content here -->
</div>
</Awaited>You can also use any custom markup inside
<Fallback>—it’s just a semantic wrapper to help with styling and behavior.
- Acts as a visual placeholder while data or content is being fetched.
- Automatically fades out when awaited content becomes available.
- Integrates seamlessly with the
Awaitedcomponent’s transition system.
Astro Awaited uses a Vite plugin during build time to:
- Parse
.astrofiles via the Astro compiler. - Detect
Fallbackcomponents missing aslotattribute. - Automatically inject
slot="fallback"into those components. - Return the transformed code.
✅ All transformations happen at build time—no runtime overhead.
MIT
Contributions are welcome! Feel free to open an issue or submit a pull request.