We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
`Phoenix.LiveView.JS` for client-side interactions
almirsarajcic
Not every click needs a server roundtrip. Toggling a dropdown, showing a modal, or hiding a deleted item are all pure UI operations — but they’re often implemented with handle_event/3 and a socket assign, adding latency for no reason.
Phoenix.LiveView.JS lets you execute these DOM operations entirely on the client, with no server ping.
alias Phoenix.LiveView.JS
# ❌ Server roundtrip just to toggle visibility
def handle_event("toggle_menu", _params, socket) do
{:noreply, assign(socket, :show_menu, !socket.assigns.show_menu)}
end
# ✅ Pure client-side, zero server roundtrip
def toggle_menu(js \\ %JS{}) do
JS.toggle(js, to: "#dropdown-menu")
end
In your template, replace phx-click="toggle_menu" with phx-click={toggle_menu()}. The server never sees this event.
JS commands are also chainable, which makes modal animations clean to implement:
alias Phoenix.LiveView.JS
def show_modal(js \\ %JS{}) do
js
|> JS.show(to: "#modal-backdrop")
|> JS.show(
to: "#modal",
transition: {"ease-out duration-200", "opacity-0 scale-95", "opacity-100 scale-100"}
)
|> JS.add_class("overflow-hidden", to: "body")
end
def hide_modal(js \\ %JS{}) do
js
|> JS.hide(to: "#modal-backdrop")
|> JS.hide(
to: "#modal",
transition: {"ease-in duration-150", "opacity-100 scale-100", "opacity-0 scale-95"}
)
|> JS.remove_class("overflow-hidden", to: "body")
end
You can also combine JS commands with a server push — useful when you want optimistic UI (hide immediately) while the server does the real work:
# Hide the item AND tell the server to delete it
def handle_delete(js \\ %JS{}, id) do
js
|> JS.hide(to: "#item-#{id}", transition: "fade-out")
|> JS.push("delete_item", value: %{id: id})
end
The full set of available commands: JS.show/2, JS.hide/2, JS.toggle/2, JS.add_class/3, JS.remove_class/3, JS.toggle_class/3, JS.set_attribute/3, JS.remove_attribute/3, JS.toggle_attribute/3, JS.dispatch/3, JS.transition/3, and JS.push/3.
Note: JS commands are DOM-patch aware — operations applied client-side survive LiveView diffs and re-renders, unlike manual DOM manipulation in JavaScript hooks.
copied to clipboard