Astro — Client Islands


One of the reasons I chose Astro was its flexibility. All I mostly need is static content generation. However, Astro provides a powerful feature — client islands. The island architecture (as it’s called) allows you to build static sites with interactive parts. Astro offers several ways to load the JavaScript needed for interactive components, which lets you load the necessary bundles only when you actually need them.

Astro allows you to write interactive components in pure JavaScript or in your favorite UI framework (Astro provides integrations for React, Vue, Svelte, Solid, and others). You can even combine them, giving you huge flexibility (again, one of the reasons I chose Astro).

Live Example

For a little showcase, I’ve built a simple live GitHub repository card with Svelte 5.

FETCHING_DATA

The component fetches data from the GitHub API. What’s more, it only hydrates when it becomes visible in the viewport (thanks to the client:visible directive — more on that below).

Client Directives

Astro provides several directives to control when client islands hydrate:

  • client:load — Hydrate immediately on page load
  • client:idle — Hydrate when the browser is idle
  • client:visible — Hydrate when the component enters the viewport
  • client:media — Hydrate based on media query
  • client:only — Skip server rendering entirely

These directives give you control over hydration. For example, some of your pages don’t even need to load any JavaScript because the user won’t scroll to the interactive part of the page. Keep in mind that this also means you must think about Core Web Vitals.

Careful with client islands

When working with client islands, one issue you might encounter is a poor score for Cumulative Layout Shift. Imagine the example above — when the card loads data from the GitHub API, it shows a “skeleton” card indicating that data is being fetched. However, if I hadn’t implemented the loading state and just displayed nothing, the whole page would “jump” once the data loaded and the card rendered. That jump hurts CLS. Always think about the interactive parts on your page and test all scenarios — data loading, data fetched, and error states (if your component works with data from APIs).

Also, one simple solution to this is to render everything on the server. Astro provides this capability as well, using server islands. But let’s keep that for another post.