Building Interactive Islands with Astro and React
Building Interactive Islands with Astro and React
Astro’s Islands architecture allows us to build mostly static sites with interactive components exactly where we need them. This approach gives us the best of both worlds: fast static sites with dynamic functionality.
What are Islands?
Islands are interactive UI components on an otherwise static page of HTML. Multiple islands can exist on a page, and each island always renders in isolation. Think of them as islands in a sea of static, server-rendered HTML.
Why Use Islands?
The Islands architecture offers several benefits:
- Better Performance: Only ship JavaScript for the interactive parts
- Faster Loading: Static content loads immediately
- Progressive Enhancement: Site works even if JavaScript fails
- Component Isolation: Each island loads independently
Interactive Example
Here’s a React component running as an island in this blog post. Try interacting with it:
Interactive Counter Example
This is a React component embedded in the MDX blog post. Click the buttons to interact!
How It Works
The counter above is a React component that only loads when it becomes visible in the viewport (using client:visible
directive). The rest of this page is static HTML.
The Component Code
import React, { useState } from 'react';
export default function InteractiveCounter({ initialCount = 0, step = 1 }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<button onClick={() => setCount(count - step)}>-{step}</button>
<span>{count}</span>
<button onClick={() => setCount(count + step)}>+{step}</button>
</div>
);
}
Using It in MDX
import InteractiveCounter from '../../components/InteractiveCounter.tsx';
<InteractiveCounter client:visible initialCount={10} step={5} />
Client Directives
Astro provides several client directives to control when components hydrate:
client:load
- Load and hydrate immediatelyclient:idle
- Load and hydrate once the page is done with initial loadclient:visible
- Load and hydrate once the component enters the viewportclient:media
- Load and hydrate once a CSS media query is metclient:only
- Skip server-rendering, only render on the client
Another Interactive Example
Let’s add another counter with different settings:
Interactive Counter Example
This is a React component embedded in the MDX blog post. Click the buttons to interact!
This one uses client:idle
so it loads after the initial page load is complete.
Best Practices
- Use the right directive: Choose the appropriate client directive based on component importance
- Minimize island size: Keep interactive components focused and small
- Prefer static when possible: Only use islands for truly interactive parts
- Lazy load heavy components: Use
client:visible
for components below the fold
Conclusion
The Islands architecture in Astro provides a powerful way to build performant websites that are mostly static but include interactive components exactly where needed. By shipping less JavaScript and hydrating components strategically, we can create fast, engaging user experiences.
Try building your own interactive islands and see how they can enhance your static sites!