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.