Directives

Directives are special attributes the compiler understands. Most work in both JSX and html ; a few keyword forms (`if`, `each`, `bind:`, `class:name`, `style:prop`) are html -only, because they have no clean, type-checkable JSX equivalent.

Events

Delegated events (one listener at the root, dispatched by the framework):

html`<button @click=${onClick}>Save</button>`;   // html`` — @event
// JSX equivalent:
<button onClick={onClick}>Save</button>;

@click and onClick are byte-identical. For a native listener (addEventListener, bypassing delegation — required for capture/once/passive) use on::

html`<div on:scroll=${onScroll}></div>`;
<div on:scroll={onScroll} />;   // JSX — on: index signature

Modifiers

Dotted modifiers work on the @/on: forms:

Modifier Effect
.capture listen in the capture phase
.once remove after the first call
.passive mark the listener passive
.prevent event.preventDefault()
.stop event.stopPropagation()
.self only when event.target === currentTarget
html`<form @submit.prevent=${save}></form>`;
html`<div on:wheel.passive=${onWheel}></div>`;

In JSX, oncapture:event is shorthand for a capture-phase native listener:

<div oncapture:click={onClick} />;

Element bindings

ref

Capture the element into a variable or callback:

let el!: HTMLInputElement;
html`<input ref=${el} />`;
html`<input ref=${(node) => (el = node)} />`;

use — custom directives

use=${fn} calls fn(element) when the element mounts; the named form passes options:

html`<div use=${tooltip}></div>`;
html`<div use:tooltip=${{ text: 'Hi' }}></div>`;
<div use:tooltip={{ text: 'Hi' }} />;   // JSX

prop: / attr: / bool:

Force how a value is applied, bypassing the property-vs-attribute heuristic. These work in both JSX and html ``:

html`<input prop:value=${text()} />`;   // always the DOM property (element.value = …)
html`<div attr:data-id=${id()} />`;     // always setAttribute
html`<button bool:disabled=${busy()} />`; // boolean attribute: present when truthy, removed when falsy
<my-widget prop:config={config()} />;
<circle attr:cx={x()} />;
<button bool:disabled={busy()} />;

.prop and ?attr (html`` shorthands)

Lit-style shorthands for the same idea:

html`<video .currentTime=${t()}></video>`;   // property binding — same as prop:
html`<button ?disabled=${busy()}></button>`; // boolean attribute — same as bool:

class and style

classList and a style object work in both surfaces:

html`<div class=${{ active: on(), big: large() }}></div>`;
html`<div style=${{ color: c(), '--x': px() }}></div>`;
<div classList={{ active: on() }} style={{ color: c() }} />;

html `` additionally offers per-name toggles:

html`<div class:active=${on()} class:big=${large()}></div>`;
html`<div style:color=${c()} style:--x=${px()}></div>`;

html — raw innerHTML

html`<div html=${markup()}></div>`;   // sets innerHTML (reactive when given an accessor)

...spread

Spread a props/attributes object (merged with mergeProps):

html`<div ...${attrs}></div>`;
<div {...attrs} />;

Control flow (html`` only)

These compile to the <Show> / <For> components — sugar for common cases.

if / else

html`
  <p if=${user()}>Welcome, ${user()!.name}</p>
  <a else href="/login">Sign in</a>
`;

if compiles to <Show when>; an immediately-following sibling with else becomes the fallback.

each / key

html`<li each=${items()}>${(item) => item.label}</li>`;

each compiles to <For each>; the ${item => …} child is the render function. Add key="id" to key the list by a field (rows are then reused by identity):

html`<li each=${rows()} key="id">${(row) => row().name}</li>`;

bind: — two-way binding

bind:value / bind:checked bind an input to a [get, set] signal tuple:

const name = createSignal('');
html`<input bind:value=${name} />`;              // value + input event
html`<input type="checkbox" bind:checked=${on} />`; // checked + change event

JSX vs html`` at a glance

Directive JSX html``
@click / onClick, on:event, modifiers
ref, use:
prop: / attr: / bool:
classList, style object, ...spread
oncapture:event
.prop, ?attr
class:name, style:prop
if / else, each / key, bind: — (use <Show>/<For>)