Pulse · Alpine-style

Event directives

@click="count++" runs an expression when the event fires. Modifiers handle the boilerplate: .prevent, .stop, .enter, .escape.

Write @event or the long form kj-on:event. Inside the expression you can use the component's state and methods, plus $event (the native event) and $el (the element).

ModifierDoes
.preventevent.preventDefault() — e.g. @submit.prevent
.stopevent.stopPropagation() — parent handlers don't see it
.enterOnly when the key is Enter
.escapeOnly when the key is Escape

Directives inside markup produced by kj-html are wired automatically, so rendered list items can carry their own @click.

Live · Keyboard-friendly to-do list

    Clicking this card counts: clicks.
    View the source for this demo
    HTML
    <div kj-data="todos">
      <form class="row" @submit.prevent="add()">
        <label for="td-in" class="sr-only">New task</label>
        <input id="td-in" type="text" kj-model="draft" @keyup.escape="draft = ''" placeholder="Enter adds · Esc clears" style="flex:1;min-width:200px">
        <button type="submit">Add</button>
      </form>
      <ul class="list-plain" kj-html="list()" aria-live="polite" style="margin-top:8px"></ul>
      <div class="td-card" @click="clicks++">
        Clicking this card counts: <b kj-text="clicks"></b> clicks.
        <button type="button" @click.stop="items = []">Clear all (.stop — the card doesn't count it)</button>
      </div>
    </div>
    JavaScript
    $.component('todos', () => ({
      draft: '', clicks: 0,
      items: ['Try Esc in the field', 'Press Enter to add a task'],
      add() {
        if (!this.draft.trim()) return;
        this.items.push(this.draft.trim());
        this.draft = '';                        // the focused field clears too
      },
      remove(i) { this.items.splice(i, 1); },
      list() {
        return this.items.map((t, i) =>
          '<li class="row" style="justify-content:space-between">' + $.escape(t) +
          ' <button type="button" @click="remove(' + i + ')" aria-label="Remove ' + $.escape(t) + '">✕</button></li>').join('');
      },
    }));

    More examples

    Directive forms

    HTML
    <button @click="open = !open">Toggle</button>
    <form @submit.prevent="save()">…</form>
    <input @keyup.enter="search($el.value)" @keyup.escape="$el.value = ''">
    <div kj-on:mouseenter="hovered = true" kj-on:mouseleave="hovered = false"></div>

    API

    @click="expr" · kj-on:input="expr" · modifiers: .prevent .stop .enter .escape

    Run an expression on an event. Modifiers call preventDefault/stopPropagation or filter keys.

    Reference: @event / kj-on:event →

    Migrating

    Coming from Alpine.jsx-on:/@ work the same. One modifier per directive; .outside, .window, .document, .once, .debounce and other key names are not included — use $event.key.

    Related features