Events
DOM event handlers in JSlop are just attributes that start with on followed by a lowercase letter.
The basics
component Counter {
state n = 0
function inc() { n++ }
view {
<button onclick={inc}>+</button>
}
}
The handler can be a function reference, an arrow function, or any expression that produces a function:
<button onclick={inc}>+</button>
<button onclick={() => n++}>+</button>
<button onclick={() => { n++; logged = true }}>+</button>
Inline mutations
Inside an event handler expression, reads and writes of state / prop identifiers are rewritten reactively. You can update state inline:
<button onclick={() => count++}>+</button>
<button onclick={() => count = 0}>reset</button>
<input oninput={e => draft = e.target.value} />
For most “wire an input back into a cell” cases you don’t need an event handler at all — use bind:value instead.
The event object
DOM event handlers receive a regular Event (or subclass — MouseEvent, InputEvent, etc.):
<form onsubmit={e => {
e.preventDefault()
save()
}}>
...
</form>
<input onkeydown={e => {
if (e.key === "Enter") submit()
}} />
There are no synthetic events — JSlop attaches real DOM listeners.
Common events
Anything the browser fires:
<button onclick={...}>
<button ondblclick={...}>
<input oninput={...}>
<input onchange={...}>
<input onfocus={...}>
<input onblur={...}>
<input onkeydown={...} onkeyup={...} onkeypress={...}>
<form onsubmit={...}>
<select onchange={...}>
<a onpointerenter={...} onpointerleave={...}>
<div onmouseover={...} onmouseout={...} onscroll={...}>
The attribute name is the standard on<event> form, lowercase.
Component callbacks
When you put on* on a component tag, it’s just a regular prop — JSlop does not auto-bind component callbacks to DOM events. The component decides what to call it:
// Stepper.jslop
component Stepper {
prop label = "?"
prop onstep = () => {}
view {
<button onclick={onstep}>{label}</button>
}
}
// parent
<Stepper label="+" onstep={inc} />
Naming is convention. Call it onstep, onclick, onclose, onaction — whatever reads clearest at the call site. The child receives whatever the parent passed and invokes it manually.
Capture phase, once, passive
Note
onclick|capture, onclick|once, onclick|passive are not implemented today. If you need them, attach the listener yourself with effect + onCleanup from @jslop/runtime, or wrap the call:
let didFire = false
function once(e) {
if (didFire) return
didFire = true
...
}
Preventing default / stopping propagation
Call the standard methods on the event:
<form onsubmit={e => {
e.preventDefault()
save()
}}>
...
</form>
<a href="/x" onclick={e => {
e.preventDefault()
navigate("/x")
}}>x</a>
Handlers in {#each}
The item binding is in scope inside the handler:
{#each todos as t (t.id)}
<li>
<button onclick={() => remove(t.id)}>×</button>
{t.text}
</li>
{/each}
t is a normal local variable inside the each-body, so reads of it aren’t rewritten — JSlop just reads the value at the point the handler fires.
See also
- Bindings — when to use
bind:valueinstead of an inline event handler. - Components —
prop onstep = () => {}pattern for component callbacks.