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

  1. 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>
  2. 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>
  3. 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

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 when requestIdleCallback is not available
  • Supports all modern browsers that implement Custom Elements v1

For more examples and use cases, check out our Examples section.