js!
The js! macro embeds raw JavaScript for cases where rs2js translation is insufficient.
LIVE
js! handlers
js! input:
Basic usage
let count = signal(0);
view! {
<button onClick={ js! {
state.count.update(c => c + 1);
}}>
"+"
</button>
}Async handlers
Lazy handlers receive (event, state, __resuma). For async code, use an explicit arrow function (required since 1.0.1 — do not rely on double-wrapping):
onClick={js!(async (_event, _state, __resuma) => {
const res = await __resuma.safeAction("save", [draft]);
if (res.ok) state.status.set("Saved");
else state.error.set(res.error);
})}Server actions
view! {
<button onClick={ js! {
const result = await __resuma.action('greet', ['World']);
state.message.set(result);
}}>
"Greet"
</button>
}Prefer __resuma.safeAction(name, args) when you want { ok, value } | { ok: false, error } without try/catch — see Error boundaries.
SPA navigation
on:change={js! {
const el = event.target;
if (!(el instanceof HTMLInputElement)) return;
await __resuma.navigate(__resuma.buildUrl("/book", { fecha: el.value }));
}}Always read form values from event.target in js! handlers — event.currentTarget is unreliable in async code.
When to use js!
- Async fetch patterns with
await __resuma.action(...) - Query-driven loader refresh via
__resuma.navigate - Browser APIs not expressible in Rust closures
- Complex client-side orchestration
Prefer rs2js when possible
Plain Rust closures in onClick are translated automatically and stay type-checked on the server side. Reach for js! only when you need full JS syntax.