Events
Brew has three related event surfaces:
- Browser DOM events —
wire:click,wire:keydown.enter, customwire:trix-change, … - Component events —
dispatch(...)on the server,@On/listeners()on the receiver - JavaScript / Alpine —
Brew.dispatch,$wire.$dispatch,x-on:….window
They share names on purpose: a server dispatch('saved') becomes a browser CustomEvent that Alpine and other components can hear.
Browser events (wire:*)
Section titled “Browser events (wire:*)”Use wire:<event-name> on any element to call a server action:
<button wire:click="save">Save</button><button wire:click.prevent="save">Save</button><button wire:dblclick="edit">Edit</button><input wire:keydown.enter="search" /><input wire:keydown.shift.enter="newline" /><div wire:keydown.escape.window="close"></div><div wire:trix-change="updated"></div><div wire:init="load">…</div>Key modifiers include .enter, .escape, .space, .tab, .shift, .ctrl, .alt, .meta / .cmd, arrow keys, .page-up / .page-down, and .slash.
| Modifier | Role |
|---|---|
.window / .document |
Listen on window / document |
.outside |
Fire when the event happens outside the element |
.self |
Only when the event target is the element |
.once |
Remove listener after first fire |
.debounce.Xms / .throttle.Xms |
Rate-limit |
.passive / .capture |
addEventListener options |
.camel / .dot |
Event name casing |
Any DOM event name works after wire:. See Actions for magic actions and confirm dialogs.
Dispatch from the server
Section titled “Dispatch from the server”Queue a browser event from an action:
fun save() { // … dispatch("post-saved", "id" to postId)}
fun notifySelf() { dispatch("refresh-ui").self()}
fun notifyChild() { dispatch("filter-changed", "q" to query).to("search-panel")}public void save() { // … dispatch("post-saved", Map.of("id", postId));}
public void notifySelf() { dispatch("refresh-ui").self();}
public void notifyChild() { dispatch("filter-changed", Map.of("q", query)).to("search-panel");}Fluent delivery:
| Method | Effect |
|---|---|
to("name") / to(Class) / component("name") |
Target a component by name |
self() |
Only this component |
ref("name") |
Target a wire:ref |
el("selector") |
Target a CSS selector |
Serialized into effects.dispatches and delivered by the client after morph.
Listen with @On and listeners()
Section titled “Listen with @On and listeners()”import org.konaframework.brew.On
class Feed : Component() { @On("post-saved") fun onSaved(id: Long) { /* … */ }
@On("post-updated.{post.id}") fun onThisPost() { /* dynamic placeholder from state */ }
override fun listeners() = mapOf( "legacy-event" to "onLegacy", )
fun onLegacy() { /* … */ }}import org.konaframework.brew.On;
public class Feed extends Component { @On("post-saved") public void onSaved(long id) { /* … */ }
@On("post-updated.{post.id}") public void onThisPost() { /* … */ }
@Override public Map<String, String> listeners() { return Map.of("legacy-event", "onLegacy"); }
public void onLegacy() { /* … */ }}On mount, Brew dehydrates listener names into effects.listeners so the client can route events. Placeholders like {post.id} are resolved from component properties.
Nested child listeners
Section titled “Nested child listeners”Listen for a child’s event on the parent tag:
<brew:editor @post-saved="refreshList" />The parent method runs when the child dispatches post-saved.
JavaScript and Alpine
Section titled “JavaScript and Alpine”// GlobalBrew.on('saved', (e) => console.log(e))Brew.dispatch('saved', { id: 1 })Brew.dispatchTo('counter', 'bump', {})
// From Alpine / $wire$wire.$on('saved', () => {})$wire.$dispatch('saved', { id: 1 })$wire.$dispatchSelf('refresh-ui')$wire.$dispatchTo('search-panel', 'filter-changed', { q: 'brew' })$wire.$dispatchRef('panel', 'close')$wire.$dispatchEl('#toast', 'show', { text: 'Done' })Alpine hears Brew events as window CustomEvents:
<div x-data x-on:post-saved.window="toast = $event.detail"> …</div>Template helpers $dispatch / $dispatchTo / $dispatchSelf are available in Alpine expressions inside a component root.
Echo / broadcasting
Section titled “Echo / broadcasting”@On("echo:channel,Event"), echo-private:, and echo-presence: integrate with Kona’s broadcasting adapter when Echo is present on the page. See the Kona broadcasting docs for channel setup; Brew only wires the listener names into the component.
Testing
Section titled “Testing”Brew.test("feed") .call("save") .assertDispatched("post-saved") .assertDispatched("post-saved") { params -> params["id"] == 42L } .assertNotDispatched("deleted")You can also dispatch(...) into a testable instance to exercise @On handlers without a browser.
- Nesting — parent/child event wiring
- Alpine.js coupling —
$wireandx-on - JavaScript runtime — hooks and interceptors