Sapling Islands
The sapling-island
web component is a lightweight solution for implementing islands architecture in your Sapling applications. It allows you to progressively hydrate parts of your page, loading JavaScript and styles only when needed.
Installation
Add the Sapling Islands script to your page via CDN:
<script type="module" src="https://sapling-is.land"></script>
Add the following CSS to ensure proper rendering of the content inside the islands:
sapling-island {
display: contents;
}
There may be some cases where you don't want display: contents
; however, in most cases it's a good idea to use it.
Overview
Islands architecture is a pattern where most of your page remains static HTML, with interactive "islands" that get hydrated with JavaScript when needed. This approach can significantly improve initial page load performance by deferring the loading of non-critical JavaScript.
Basic Usage
Wrap any content that requires JavaScript or additional styles in a sapling-island
component:
<sapling-island loading="onload">
<template>
<script src="/scripts/interactive.js" type="module"></script>
<style>
/* Styles that are only needed for this interactive component */
</style>
</template>
<div>Your interactive content here</div>
</sapling-island>
Loading Strategies
The component supports several loading strategies through the loading
attribute:
Load Immediately
Loads immediately when the page loads:
<sapling-island loading="onload">
<template>
<script src="/scripts/immediate.js" type="module"></script>
</template>
</sapling-island>
Visible
Loads when the component becomes visible in the viewport:
<sapling-island loading="onvisible">
<template>
<script src="/scripts/lazy.js" type="module"></script>
</template>
</sapling-island>
Idle
Loads when the browser is idle:
<sapling-island loading="idle">
<template>
<script src="/scripts/low-priority.js" type="module"></script>
</template>
</sapling-island>
Media Query
Loads when a media query condition is met:
<sapling-island loading="(min-width: 768px)">
<template>
<script src="/scripts/desktop-only.js" type="module"></script>
</template>
</sapling-island>
Timeout Option
You can specify a timeout for loading strategies using the timeout
attribute:
<sapling-island loading="onvisible" timeout="5000">
<template>
<script src="/scripts/important.js" type="module"></script>
</template>
</sapling-island>
Events
The component dispatches a island:hydrated
event when hydration is complete:
document.querySelector('sapling-island').addEventListener('island:hydrated', () => {
console.log('Island has been hydrated');
});
Best Practices
Template Content Only Only place
<script>
and<style>
tags inside the<template>
element. This ensures they are only loaded when needed:<sapling-island loading="onvisible"> <template> <!-- Scripts and styles go here --> <script src="/scripts/feature.js" type="module"></script> <style>/* Feature styles */</style> </template> <!-- Actual content goes outside template --> <div class="feature">...</div> </sapling-island>
Progressive Enhancement Design your islands to enhance existing static content rather than being required for basic functionality:
<!-- Static content works without JavaScript --> <div class="content">Static content</div> <!-- Interactive features are added through islands --> <sapling-island loading="onvisible"> <template> <script src="/scripts/enhance.js" type="module"></script> </template> <div class="enhancement">Interactive features</div> </sapling-island>
Performance Considerations
- Use
onvisible
for below-the-fold content - Use
idle
for non-critical enhancements - Use media queries for device-specific features (mobile navigation, desktop features, etc.)
- Set appropriate timeouts for critical features
- Use
Example: Interactive Comments Section
Here's a complete example of using sapling-island
for a comments section:
<sapling-island loading="onvisible" timeout="3000">
<template>
<script src="/scripts/comments.js" type="module"></script>
<style>
.comments-form { /* Styles for the form */ }
.comments-list { /* Styles for the list */ }
</style>
</template>
<div class="comments-section">
<h2>Comments</h2>
<div class="comments-list">
<!-- Static comments rendered server-side -->
</div>
<div class="comments-form">
<!-- Form becomes interactive after hydration -->
</div>
</div>
</sapling-island>
Browser Support
The sapling-island
component uses standard web APIs and includes fallbacks for broader browser support:
- Uses
IntersectionObserver
for visibility detection - Falls back to
setTimeout
whenrequestIdleCallback
is not available - Supports all modern browsers that implement Custom Elements v1
For more examples and use cases, check out our Examples section.