By default, all reactive scripts on a page share a single reactive scope - top-level variables can be referenced from anywhere. Reactive islands create isolated scopes where variables are contained within the island. This is perfect for:
Add is="reactive-island" to any container element to create an isolated reactive scope:
<div is="reactive-island">
<script type="module" is="reactive">
const count = mutable(0);
const increment = () => count.value++;
const decrement = () => count.value--;
</script>
<script type="module" is="reactive">
<div>
<button onclick={decrement}>-</button>
<span style="margin: 0 1em">{count}</span>
<button onclick={increment}>+</button>
</div>
</script>
</div>
Each island below contains identical code - the same count, increment, and decrement declarations. Because each island has its own reactive scope, these variables don't conflict:
Reactive islands work perfectly with HTMX. When HTMX swaps in new HTML containing a reactive island, the island automatically initializes:
<!-- Server returns this HTML fragment -->
<div is="reactive-island" hx-swap-oob="true" id="widget">
<script type="module" is="reactive">
const value = view(<input type="range" min="0" max="100"/>);
</script>
<script type="module" is="reactive">
`Value: ${value}`
</script>
</div>
Unpoly can swap reactive islands just like any other fragment:
<a href="/widget" up-target="#widget">Load Widget</a>
<div id="widget">
<!-- This will be replaced with a reactive island -->
</div>
Datastar uses Server-Sent Events to stream HTML updates. Reactive islands can be streamed as complete components:
<!-- Streamed via SSE -->
<div is="reactive-island" data-star-swap="innerHTML">
<script type="module" is="reactive">
// Self-contained reactive component
</script>
</div>
When the HTML transformer encounters a is="reactive-island" element:
is="reactive" scripts within are collected| Aspect | Full SPA | Reactive Islands |
|---|---|---|
| Initial page load | Blank until JS loads | Instant server-rendered content |
| SEO | Requires SSR setup | Works out of the box |
| Bundle size | Large framework overhead | |
| Hydration | Full page hydration | Only interactive parts |
| Complexity | Build pipeline required | Optional - works at runtime |