Lazy Server Islands
Server islands marked with mochi:defer:visible only fetch their HTML when the wrapper scrolls into view, via an IntersectionObserver. Each island is fetched independently from /_mochi/island/... — open the Network panel and scroll to watch the requests fire on demand. The first island uses rootMargin to start fetching 200px before it enters the viewport.
Scroll down to trigger each fetch. The IntersectionObserver fires per-island.
Island #1 — rootMargin: '200px'
Loading server island
Island #2
Loading server island
Island #3
Loading server island
Island #4
Loading server island
Island #5
Loading server island
<script>
import LazyServerDemo from './LazyServerDemo.svelte';
</script>
<p class="hint">Scroll down to trigger each fetch. The IntersectionObserver fires per-island.</p>
<div class="stack">
<div class="item">
<h3>Island #1 — <code>rootMargin: '200px'</code></h3>
<LazyServerDemo mochi:defer:visible={{ rootMargin: '200px' }} index={1}>
<div class="island-loading">Loading server island<span class="dots"></span></div>
</LazyServerDemo>
</div>
{#each [2, 3, 4, 5] as i (i)}
<div class="spacer"></div>
<div class="item">
<h3>Island #{i}</h3>
<LazyServerDemo mochi:defer:visible index={i}>
<div class="island-loading">Loading server island<span class="dots"></span></div>
</LazyServerDemo>
</div>
{/each}
</div>
Styles
<style>
.hint {
font-size: 0.9rem;
color: var(--text-muted);
margin: 0 0 1rem;
}
.stack {
display: flex;
flex-direction: column;
}
.item h3 {
font-size: 0.95rem;
font-weight: 600;
color: var(--text-muted);
margin: 0 0 0.5rem;
}
.item h3 code {
font-size: 0.85em;
background: var(--surface-muted);
padding: 0.1em 0.4em;
border-radius: 4px;
}
.spacer {
height: 70vh;
}
.island-loading {
padding: 1rem;
border: 2px dashed var(--border-strong);
border-radius: var(--radius-md);
background: var(--surface-muted);
color: var(--text-subtle);
font-style: italic;
text-align: center;
}
.dots::after {
content: '';
display: inline-block;
width: 1.5em;
text-align: left;
animation: dots 1.2s steps(4, end) infinite;
}
@keyframes dots {
0% {
content: '';
}
25% {
content: '.';
}
50% {
content: '..';
}
75% {
content: '...';
}
}
</style>
More demos