Islands Architecture

The page below is static, server-rendered HTML. The three interactive widgets are tina4-js Web Components that hydrate on their own the moment the script defines them. Each island is shadow-DOM encapsulated: it brings its own markup and its own styles.

🎧 server-rendered

Wireless Headphones

$79.99

Over-ear, 40-hour battery, active noise cancellation. This copy, the price, and the layout arrived as static HTML. The stars, the cart, and the live viewer count are islands.

🌴 Why islands

Each widget is a Tina4Element that calls customElements.define(). Drop its tag into any server-rendered page - PHP, Twig, Go templates, plain HTML - and it upgrades in place. An island ships around 2 KB of its own logic instead of booting a whole framework for the entire page. It reads its own attributes, owns its own signals, scopes its own styles, and cleans up when removed.

How it works — View Source

import { Tina4Element, signal, html } from 'tina4js';

class AddToCart extends Tina4Element {
  static props  = { sku: String, price: Number };  // attr names == keys
  static styles = \`.buy { background: var(--primary); }\`;  // scoped to the shadow root
  qty    = signal(1);   // each island owns its state
  inCart = signal(0);

  render() {
    return html\`
      <button @click=\${() => this.qty.value++}>+</button>
      <span>\${this.qty}</span>
      <button class="buy" @click=\${() => this.inCart.value += this.qty.value}>
        Add \${() => this.prop('price')}
      </button>
    \`;
  }
}
customElements.define('add-to-cart', AddToCart);

Then in any server page: <add-to-cart sku="WH-100" price="79.99"></add-to-cart>