Alpine
Home-UI does not know Alpine exists. It works with Alpine because it does two things Alpine expects of a native control:
- Value-carrying controls emit native-named
inputandchange, sox-modelbinds with no adapter. - Every event is dispatched with
bubbles: trueandcomposed: true, so it crosses the shadow boundary and an ancestorx-onsees it.
Values with x-model
Section titled “Values with x-model”<div x-data="{ email: 'dev@example.com' }"> <hui-input name="email" type="email" x-model="email"></hui-input> <p>You entered <span x-text="email"></span></p></div>x-model listens for input on the host and writes the value property back. A component stops the internal native control’s own event at its boundary and dispatches one synthetic input/change from the host, so Alpine receives exactly one event per interaction and never a duplicate.
Events with x-on
Section titled “Events with x-on”Component-specific events keep the hui- prefix. All carry detail where there is something to carry:
<div x-data="{ course: null }" x-on:hui-select="course = $event.detail.value"> <hui-calendar name="courseDate"></hui-calendar></div>| Event | From | Detail |
|---|---|---|
input, change | every value control | none; read the host’s value |
hui-select | hui-dropdown-menu, hui-calendar, hui-command | { value } (and item/option) |
hui-open, hui-close | dialog, popover, select, tabs, command | none |
hui-dismiss | dialog | none; cancelable — call $event.preventDefault() to refuse |
hui-toast-dismiss | toast | none |
hui-confirm, hui-cancel | confirm-action | none |
hui-theme-change | theme-toggle | none |
Because every event bubbles and is composed, you can listen on a container rather than on each component:
<form x-on:change="dirty = true"> <hui-input name="a"></hui-input> <hui-switch name="b"></hui-switch></form>Visibility with x-show
Section titled “Visibility with x-show”x-show toggles display on the component’s host element. That is safe: a hidden control is not focusable, and re-showing it does not disturb its internal state or listeners.
Source
<div style="display:flex;flex-direction:column;gap:.75rem;max-width:22rem"><hui-input name="email" type="email" value="dev@example.com" aria-label="Email"></hui-input><hui-switch name="subscribe" checked>Subscribe</hui-switch></div>No dependency
Section titled “No dependency”With Alpine absent, every component behaves identically — there is no window.Alpine read anywhere in the library. Two components on one page emitting the same event are distinguished by their host element ($event.target). Alpine replacing a parent must not orphan a component’s listeners; teardown is handled in disconnectedCallback, so it does not.