Events Reference

On this page 17

Event handlers in stx use the @event syntax to bind DOM events to expressions or function calls. They support modifiers for common patterns like preventDefault, key filtering, and one-shot handlers.

Basic Syntax

@event.modifier1.modifier2="expression"

The expression is evaluated in the component's reactive scope. The native DOM event is available as $event.

Event Handlers

Click

<button @click="handleClick()">Click me</button>
<button @click="count.set(count() + 1)">Increment</button>
<button @click="open = !open">Toggle</button>

Submit

<form @submit.prevent="handleSubmit($event)">
  <input type="text" x-model="query" />
  <button type="submit">Search</button>
</form>

Keyboard

<input @keydown.enter="search()" />
<input @keydown.escape="close()" />
<div @keydown.space="togglePlay()"></div>

Mouse

<div @mouseenter="showTooltip()" @mouseleave="hideTooltip()"></div>
<div @dblclick="editItem()"></div>

Input / Change

<input @input="onInput($event)" />
<select @change="onSelect($event)"></select>

Supported Events

The runtime recognizes these event names directly:

EventDescription
clickMouse click
dblclickDouble click
mousedownMouse button pressed
mouseupMouse button released
mousemoveMouse moved
mouseenterMouse entered element
mouseleaveMouse left element
keydownKey pressed
keyupKey released
keypressKey pressed (deprecated, use keydown)
inputInput value changed
changeValue committed (blur or select)
submitForm submitted
focusElement focused
blurElement lost focus
scrollElement scrolled
resizeWindow resized
touchstartTouch began
touchendTouch ended
touchmoveTouch moved
contextmenuRight-click / context menu
wheelMouse wheel scrolled
pointerdownPointer pressed
pointerupPointer released
pointermovePointer moved

Modifiers

Modifiers are chained after the event name with dots.

Action Modifiers

ModifierEffect
.preventCalls event.preventDefault()
.stopCalls event.stopPropagation()
.onceHandler fires only once, then is removed
<a @click.prevent="navigate('/about')">About</a>
<div @click.stop="handleInner()">Won't bubble</div>
<button @click.once="initialize()">Init (once)</button>
<form @submit.prevent.stop="handleSubmit($event)">...</form>

Key Modifiers

Filter keyboard events by key. Only fires when the specified key matches event.key.

Modifierevent.key value
.enterEnter
.tabTab
.escapeEscape
.space (space character)
.upArrowUp
.downArrowDown
.leftArrowLeft
.rightArrowRight
.deleteDelete
.backspaceBackspace
<input @keydown.enter="submitForm()" />
<input @keydown.escape="clearInput()" />
<div @keydown.up="selectPrevious()" @keydown.down="selectNext()"></div>
<div @keydown.space="toggleSelection()"></div>

System Modifiers

Require a system modifier key to be held.

ModifierCheck
.ctrlevent.ctrlKey
.altevent.altKey
.shiftevent.shiftKey
.metaevent.metaKey (Cmd on macOS, Win on Windows)
<input @keydown.ctrl.enter="submitAndClose()" />
<div @click.meta="openInNewTab()"></div>
<button @click.shift="selectRange()"></button>

Combining Modifiers

Modifiers can be combined freely:

<form @submit.prevent.stop="handleSubmit($event)"></form>
<input @keydown.ctrl.shift.enter="executeCommand()" />
<a @click.prevent.once="trackFirstClick()">Link</a>

The $event Object

The native DOM event is available as $event in handler expressions:

<input @input="search($event.target.value)" />
<div @click="handleClick($event.clientX, $event.clientY)"></div>
<form @submit.prevent="onSubmit($event)"></form>

Signal Writeback

When the handler expression is a direct assignment to a variable, stx detects this and writes back through signal.set() automatically:

<button @click="count = count + 1">Increment</button>
<button @click="open = !open">Toggle</button>
<button @click="name = 'Alice'">Set name</button>

The writeback check uses the pattern /^[a-zA-Z_$]\w*\s*=/ — it only triggers for direct variable assignments like count = ... or open = ....

Function calls do not trigger writeback:

<!-- These call functions that internally use signal.set() -->
<button @click="increment()">+1</button>
<button @click="store.toggle()">Toggle</button>

Warning: The writeback mechanism exists specifically for inline assignment expressions. If a function call expression were to trigger writeback, it would reset the signal to its pre-handler value, undoing the function's internal signal.set() calls. The isDirectAssignment guard prevents this.

Component Events (defineEmits)

Components can emit custom events to parent templates:

<!-- ChildComponent.stx -->
<script>
const emit = defineEmits()

function handleClick() {
  emit('select', { id: 42, name: 'Item' })
}
</script>

<button @click="handleClick()">Select</button>
<!-- Parent usage -->
<ChildComponent @select="onItemSelected($event.detail)" />

Emitted events use CustomEvent with bubbles: true for DOM propagation. The @event attributes on component tags are forwarded to the component's root element.

Double-Bind Guard

Event handlers have guards (el.__stx_evt_<event>) to prevent duplicate binding when processElement runs multiple times on the same element. This is an internal safeguard — no action required from users.