controller() intrinsic — a ResizeObserver reactive controller with hostConnected/hostDisconnected lifecycle, writes routed through an action.
stateactioncontrollercontroller.describeinterpolationThis recipe doesn't have a hydrated island in the demo gallery yet. An in-browser, WASM-compiled playground (edit this source and re-render live) is planned as a follow-up — read the real source below.
// controller — controller() intrinsic wrapping a ResizeObserver reactive controller
@state {
let width = state(0)
let height = state(0)
const setSize = action((w: number, h: number) => {
width = w
height = h
})
const resizeObserver = controller({ describe: 'Tracks host size via ResizeObserver' }, () => {
let observer: ResizeObserver | null = null
return {
hostConnected: () => {
observer = new ResizeObserver((entries) => {
const rect = entries[0]?.contentRect
setSize(Math.round(rect?.width ?? 0), Math.round(rect?.height ?? 0))
})
observer.observe((ctx.host as ShadowRoot).host)
},
hostDisconnected: () => {
observer?.disconnect()
observer = null
},
}
})
}
@template {
<div class="controller-demo">
<div class="resize-box">
<p class="dim">Width: <strong>{width}px</strong></p>
<p class="dim">Height: <strong>{height}px</strong></p>
<p class="hint">Resize the component to see updates.</p>
</div>
</div>
}
@style {
.controller-demo { padding: 1rem; resize: both; overflow: auto; border: 2px dashed var(--border, #ccc); min-width: 200px; min-height: 100px; }
.resize-box { display: grid; gap: 0.25rem; }
.dim { margin: 0; font-family: monospace; font-size: 0.9rem; }
.hint { margin: 0.5rem 0 0; font-size: 0.8rem; color: var(--muted, #888); }
}stateevents