Hybrid SSR + CSR Islands

One page, server-rendered shell, two client islands.

SSR Shell

This text is server-rendered before hydration.

Rendered at: 2026-04-17 08:35:47

PHP
<?php $bgColor = state('#1f2937'); $status = state('Waiting for next query...'); $colorRes = state([]); $httpStatus = state(0); $jokeRes = state([]); $jokeText = state('Click the button to load a joke.'); $jokeStatus = state('Idle'); $jokeHttpStatus = state(0); $islandOne = client(el('div', [ cls('glass p-3 rounded-2 mb-4'), attrs(['id' => 'color-poller']), \Thorm\style([ 'background' => read($bgColor), 'color' => read($color), 'transition' => 'background 300ms ease', ]), ], [ el('h2', [cls('h5 mb-2')], [text('Island 1: Server Color Poll')]), el('p', [cls('mb-1')], [text(read($status))]), el('p', [cls('mb-0 small')], [ text(concat('HTTP status: ', read($httpStatus))), ]), ])); $islandTwo = client(el('div', [ cls('glass p-3 rounded-2'), attrs(['id' => 'joke-island']), \Thorm\style([ 'background' => '#ffffff', 'color' => '#1f2937', 'transition' => 'all 250ms ease', ]), ], [ el('h2', [cls('h5 mb-2')], [ text('Island 2: Joke API (click)'), a([cls('px-3'), attrs(['href' => 'https://jokeapi.dev', 'target' => '_blank'])], [text('jokeapi.dev')]), ]), el('p', [cls('mb-1')], [text(read($jokeStatus))]), el('p', [cls('mb-2')], [text(read($jokeText))]), el('p', [cls('small text-muted mb-2')], [text(concat('HTTP status: ', read($jokeHttpStatus)))]), el('button', [ cls('btn btn-dark btn-sm'), on('click', task([ set($jokeStatus, val('Querying jokeapi.dev...'), true), http( val('https://v2.jokeapi.dev/joke/Any?type=single&safe-mode'), 'GET', $jokeRes, $jokeHttpStatus, null, null, 'json', true ), ])), ], [text('Get New Joke')]), ])); $app = el('div', [cls('container my-4')], [ // SSR shell div([cls('glass p-3 rounded-2 mb-4')], [ el('h2', [cls('h5 mb-2')], [text('SSR Shell')]), el('p', [cls('mb-1')], [text('This text is server-rendered before hydration.')]), el('p', [cls('mb-0 small text-muted')], [text('Rendered at: ' . $renderedAt)]), ]), // Island 1: query server every 3s for a color $islandOne, // Island 2: click to request a joke from jokeapi.dev $islandTwo, every(10000, [ set($status, val('Querying server...'), true), delay(700, [ http(val('/api/color'), 'GET', $colorRes, $httpStatus, null, null, 'json', true) ]), ]), watch(read($colorRes), [ set($bgColor, get(read($colorRes), 'color'), true), set($status, concat('Received new color: ', get(read($colorRes), 'color')), true), ]), watch(read($jokeRes), [ set($jokeText, cond(get(read($jokeRes), 'error'), val('No joke received.'), get(read($jokeRes), 'joke')), true), set($jokeStatus, val('Received joke.'), true), ]), ]);