Client Boundaries
The order of preference in Vango is:
server-driven UI
hook
island
WASM
That order is a correctness gradient, not an aesthetic preference.
Hooks
Hooks attach client behavior to server-owned DOM.
1Ul(
2 Hook("Sortable", map[string]any{
3 "handle": ".drag-handle",
4 }),
5 OnEventValidated("reorder", reorderValidator, func(e vango.HookEvent) {
6 from := e.Int("fromIndex")
7 to := e.Int("toIndex")
8 reorder(from, to)
9 }),
10)
Use hooks for:
drag and drop
focus traps
dropdown behavior
tooltips
high-frequency interaction polish
Hooks must not take structural ownership of the subtree.
Islands
Use islands when a client runtime must own the DOM subtree.
1Div(
2 JSIsland("rich-editor", map[string]any{
3 "content": content.Get(),
4 }),
5 OnIslandMessageValidated(validateEditorMessage, func(msg vango.IslandMessage) {
6 // handle validated message
7 }),
8)
Rules:
island props must encode to a JSON object
Vango does not patch inside the island boundary
communication is message-based
stable list identity is mandatory if islands appear inside dynamic lists
WASM boundaries
Use WASM when client-local execution is the actual point, usually for latency-sensitive or offline-capable behavior.
Rules largely mirror islands:
props encode to a JSON object
communication is message-based
use it only when a hook or island is not enough
Standard hook wrappers
Standard hook wrappers remain available, but the preferred authoring model is still the direct app-authoring surface in vango, setup, and el.
Validation is mandatory
Hook, island, and WASM payloads are untrusted input.
In non-dev mode, reachable client-boundary sinks must be validator-covered. Use one of the validator-supported patterns instead of accepting arbitrary payloads.
Ownership mistakes to avoid
Do not:
rewrite server-owned DOM after Vango boots
use inline scripts to repair mismatches
keep retrying client mutation until patches happen to line up
use a hook when a library really needs subtree ownership
Repeated reloads here are correctness failures, not a signal to add more reload logic.
Choosing the smallest boundary
stay server-driven if possible
use a hook for behavior on server-owned DOM
use an island when a client library must own structure
use WASM when local execution or offline behavior is the real requirement
If you are introducing persistence or deploy-sensitive state, continue to Persistence and Deploys.