Description: AlpineJS allows components to communicate effectively using custom browser events. This is crucial for decoupling components and enabling interactions like parent-child, child-parent, or even between sibling components. You can send (dispatch) events with data and listen for them on the component itself, its ancestors, or globally on the `window` object.
$dispatch('eventName', { detail: 'data' }): This magic property is used to send (dispatch) a custom browser event from within an Alpine component.
'eventName': A string representing the name of your custom event (e.g., 'item-selected', 'form-submitted').{ detail: 'data' }: An optional second argument, an object whose detail property contains any data you want to pass along with the event. The data can be any JavaScript value (string, number, object, array). This is the standard way to pass data with custom events.
For example: this.$dispatch('user-updated', { id: 1, name: 'Alice' });
x-on:eventName="handleEvent" (or shorthand @eventName): This directive is used to listen for custom events.
handleEvent can be an expression directly in the HTML or a method defined in your component's data.
For example: <div x-data="{ message: '' }" @my-custom-event="message = event.detail.text">...</div>
x-on:eventName.window="handleGlobalEvent" (or shorthand @eventName.window): This directive modifier allows you to listen for events dispatched on the global window object.
window.dispatchEvent(new CustomEvent('global-alert', { detail: { message: 'Something happened!' }})); Or, from within an Alpine component for convenience, you can dispatch to `window` directly if the listener also listens on window using `this.$dispatch` but this isn't standard `$dispatch` behavior for non-window listeners. A more robust way is to ensure the dispatch occurs on `window`.
event.detail: When an event listener (e.g., handleEvent(event)) receives a custom event dispatched with data, that data is accessible through the event.detail property.
$dispatch('foo', { bar: 'baz' }), then in your listener, event.detail would be { bar: 'baz' }, and you'd access baz via event.detail.bar.
Events dispatched with $dispatch only bubble up the DOM tree by default: If a child dispatches an event, only its direct parent and further ancestors can catch it with a simple @eventName. Sibling components won't hear it. For sibling communication:
window object (e.g., via this.$dispatch('myevent', data, { bubbles: false, target: window }) or more simply, window.dispatchEvent(new CustomEvent('myevent', { detail: data }))) and have the sibling listen with @myevent.window. This is similar to a global signal or message bus.
Forgetting to access data via event.detail: When you dispatch an event with data using this.$dispatch('myevent', { some: 'data' }), the listener callback receives an Event object. Your payload is nested inside event.detail. So, to access 'data', you'd use event.detail.some not event.some. This is a common point of confusion.
Overusing global window events for localized component communication: While .window events are powerful for cross-cutting concerns (like a global notification system), using them for simple parent-child or closely-related component communication can make data flow harder to trace and debug. It's like using global variables everywhere in Python when local scope or direct parameter passing would be clearer. For direct parent-child interaction, standard $dispatch (from child) and @event-name (on parent) is often cleaner and more maintainable.
Selected Item:
ID:
Source:
This button dispatches an event globally to the window object, which the notification bar listens for.