Portable island bindings
A marked import … with { hydrate } rewrites the binding itself into a
portable island component. Put several in a dictionary or barrel, pick one into a capitalized
binding, and render <Active /> — each stays a real region as long as the
usage is at page level.
Do not pass constructors across an island boundary as props — they will not devalue. Keep a
small controls island that only receives serializable labels and the active key, and navigate
with ?widget= links (works with JS off; the SPA router soft-navs when JS is on).
Nesting an island import inside another island degrades to a shared interactive tree — these
widgets are imported on the page shell so the selected one is a true region.
Authoring
<script>
import Pulse from '$lib/Pulse.svelte' with { hydrate: 'load' };
import Ticker from '$lib/Ticker.svelte' with { hydrate: 'load' };
import Notch from '$lib/Notch.svelte' with { hydrate: 'load' };
// Controls island: serializable props only — never pass constructors across.
import Controls from '$lib/Controls.svelte' with { hydrate: 'load' };
const registry = { pulse: Pulse, ticker: Ticker, notch: Notch };
const barrel = [
{ key: 'pulse', label: 'Pulse', Comp: Pulse },
{ key: 'ticker', label: 'Ticker', Comp: Ticker },
{ key: 'notch', label: 'Notch', Comp: Notch }
];
// active comes from load via ?widget= (default first key)
let { active } = $props();
const Active = $derived(registry[active]);
const items = barrel.map(({ key, label }) => ({ key, label }));
</script>
<Controls {active} {items} />
<Active />