Skip to content
Brew

JavaScript runtime

Brew’s client runtime is an ESM/IIFE bundle built on Alpine.js. The default script tag loads Alpine + Brew plugins and calls Brew.start() on DOMContentLoaded.

After the script loads:

window.Brew
window.Alpine

Lifecycle events on document:

Event When
brew:init / brew:initializing Before Alpine plugins and root selectors are wired — register hooks/directives here
brew:initialized After Alpine.start() and components are live
Brew.find(id)
Brew.first()
Brew.getByName('counter')
Brew.all()
Brew.navigate('/posts')
Brew.dispatch('saved', { id: 1 })
Brew.dispatchTo('counter', 'bump', {})
Brew.on('saved', handler)

Every component root exposes $wire through Alpine (magic name wire):

API Role
$wire.prop Read / assign ephemeral state
$wire.$get(path) Deep read
$wire.$set(path, value, live?) Deep set; live triggers a round-trip
$wire.$toggle(prop) Flip boolean
$wire.$call(method, …args) Invoke action
$wire.method(…args) Same as $call
$wire.$refresh() Re-render
$wire.$commit() Flush pending updates
$wire.$el / $wire.$id Root element / id
$wire.$watch(path, fn) Watch state
$wire.$hook(name, fn) Component-scoped hook
$wire.$errors Validation bag (has / first / get / all / clear)
$wire.$refs / $wire.$refs(name) Elements marked wire:ref
$wire.$dirty(path?) Whether ephemeral state diverges from the last server snapshot
$wire.$on / $wire.$dispatch* Event bridge (see Events)
$wire.$entangle(name, live?) Alpine ↔ Brew two-way binding
$wire.$intercept / $interceptAction / $interceptMessage / $interceptRequest Per-component request interceptors
$wire.$js Access queued JS evaluation helpers
$wire.$island(name) Target an island re-render (when using islands)
document.addEventListener('brew:init', () => {
Brew.hook('commit', ({ component, respond }) => { /* … */ })
Brew.hook('request', ({ respond }) => { /* … */ })
Brew.hook('morph', ({ el, component }) => { /* … */ })
Brew.hook('morph.updating', ({ el, toEl, component }) => {})
Brew.hook('component.init', ({ component, cleanup }) => {})
Brew.hook('element.init', ({ el, component }) => {})
Brew.hook('effect', ({ component, effects }) => {})
})

Morph sub-hooks: morph.updated, morph.removing, morph.removed, morph.adding, morph.added.

Prefer interceptors for request lifecycle control:

Brew.interceptAction(({ action, onCancel }) => { /* … */ })
Brew.interceptMessage(({ message, cancel, onSuccess }) => { /* … */ })
Brew.interceptRequest(({ request, onError, onFailure }) => { /* … */ })

Legacy request / commit hooks remain for older integrations.

Brew.directive('tooltip', ({ el, directive, component, cleanup }) => {
// wire:tooltip="…"
})
Group Directives
Binding wire:model (+ modifiers), wire:show, wire:text, wire:bind:*
Actions wire:click, wire:submit, any wire:<event>, wire:init, wire:confirm
UX wire:loading, wire:dirty, wire:offline, wire:cloak, wire:poll, wire:intersect, wire:sort
Morph wire:key, wire:ignore, wire:replace, wire:transition, wire:stream, wire:ref
Navigate wire:navigate, wire:current, wire:scroll
Islands wire:island (+ .append / .prepend)
  • Keyed by wire:key and wire:id
  • Respects wire:ignore / wire:ignore.self / wire:ignore.children
  • wire:replace / wire:replace.self swaps instead of morphing
  • wire:transition + effects.transition participate in the View Transitions API when available
  • Block markers from Crema keep loops/conditionals stable
Response Client behaviour
419 (expired / checksum) Page-expired prompt to refresh
500 (when app.debug) Debug modal with details
Custom onError / request interceptors can short-circuit

If you bundle Brew yourself, set window.brewScriptConfig (or emit @brewScriptConfig) and call Brew.start() after your Alpine setup. The default auto-start is skipped when script config is present.

import { Brew, Alpine } from '@konaframework/brew'
// optional: Alpine.plugin(yourPlugin)
Brew.start()

Bundled Alpine plugins at start: morph, intersect, sort, resize, collapse, anchor, focus, persist, mask.