Skip to content

LiveView

The LiveView adapter uses a dual-package architecture (npm + Hex) to bridge Voidable custom events to Phoenix LiveView’s server-side event handling.

Install the JavaScript package:

Terminal window
npm install @voidable/ui @voidable/theme @voidable/ui-liveview

Add the Hex package to mix.exs:

defp deps do
[
{:live_voidable, "~> 0.1.0"}
]
end

Add the VoidEvent hook to your LiveSocket:

import { VoidHooks } from '@voidable/ui-liveview';
let liveSocket = new LiveSocket('/live', Socket, {
hooks: { ...VoidHooks }
});

The hook listens for Voidable custom events on the element and forwards them to the server via pushEvent.

Attach the hook with phx-hook and add phx-update="ignore" to prevent LiveView from clobbering client-managed state:

<void-button
variant="filled"
phx-hook="VoidEvent"
phx-update="ignore"
data-void-events="void-click"
>
Submit
</void-button>
<void-input
placeholder="Search"
phx-hook="VoidEvent"
phx-update="ignore"
data-void-events="void-change"
></void-input>

Events arrive as standard LiveView events:

def handle_event("void-click", _params, socket) do
{:noreply, assign(socket, :submitted, true)}
end
def handle_event("void-change", %{"value" => value}, socket) do
{:noreply, assign(socket, :query, value)}
end

VoidDOM is a separate export from @voidable/ui-liveview (not part of VoidHooks). Wire it into your LiveSocket constructor via the dom option to prevent LiveView from clobbering client-managed state (open dialogs, checked states, ARIA attributes) during morphdom updates:

import { VoidHooks, VoidDOM } from '@voidable/ui-liveview';
let liveSocket = new LiveSocket('/live', Socket, {
hooks: { ...VoidHooks },
dom: {
onBeforeElUpdated(from, to) {
VoidDOM.onBeforeElUpdated(from, to);
},
},
});

If you need more granular control, you can still add phx-update="ignore" to individual <void-*> elements, but VoidDOM handles this globally and is the recommended approach.