Easy UI Toggling with LiveView JS Commands · The Phoenix Files
The Toggling UI Element with LiveView
Here’s Sophie DeBenedetto, co-author of Programming Phoenix LiveView with a deep dive into building a toggling UI element with LiveView’s JS.toggle command.
LiveView empowers developers to be more productive by keeping your mind focused on the server while building rich interactive UIs. Recently, LiveView has improved its ability to manage client-side interactions through JS commands. This post will guide you through building a toggle feature using JS.toggle.
The Problem
You want to toggle the appearance of content in response to user interactions. For example, showing/hiding a search form when clicking the “search” icon. Without JS commands, you’d need to send events to the server to manage the UI state.
The Solution
The Phoenix.LiveView.JS module provides functionality to invoke client-side operations in response to LiveView events. It abstracts common JS interactions like showing/hiding content, adding/removing classes, and setting CSS attributes.
Example: Toggling a Form
We'll look at an example to create a toggling feature for a hidden form:
# lib/live_library_web/live/book_live/search_component.html.heex
<.form
let={f}
for={@search_changeset}
id="book-search-form"
phx-submit="search"
phx-target={@myself}
class={@search_class} >
To make the form hidden on page load, we’ll use CSS:
/* assets/css/app.css */
#book-search-form {
display: none;
}
Now, let’s make it toggle using Phoenix.LiveView.JS.toggle/1:
def icon(assigns) do
~H"""
<i phx-click={JS.toggle(to: "#book-search-form")} class="bi bi-search"></i>
"""
end
Now, clicking the search icon will toggle the form's visibility.
LiveView JS Commands Under the Hood
The JS.toggle/1 function generates a Phoenix.LiveView.JS struct for toggling:
%Phoenix.LiveView.JS{
ops: [
[
"toggle",
%{
display: nil,
ins: [[], [], []],
outs: [[], [], []],
time: 200,
to: "#book-search-form"
}
]
]
}
LiveView binds the phx-click event to the appropriate JS actions when rendering the template.
Trigger Client- and Server-Side Interactions Together
You can chain JS commands to push messages to the server while toggling the search form on the client:
def icon(assigns) do
~H"""
<i phx-click={JS.push("toggle_book_search", target: @target) |> JS.toggle(to: "#book-search-form")} class="bi bi-search"></i>
"""
end
This allows the search form to toggle and URL updates without forcing a page reload. The event handler for "toggle_book_search" can manage the URL changes conveniently:
def handle_event("toggle_book_search", _value, socket) do
if socket.assigns.search_class == "show" do
{:noreply, push_patch(socket, to: "/books")}
else
{:noreply, push_patch(socket, to: "/books?search")}
end
end
This approach fosters a seamless user experience where interactions feel fluid without unnecessary reloads.
JS Commands Give Us Simple and Powerful Client-Side Interactions
LiveView abstracts common JS functionalities, allowing you to implement features without writing JavaScript. Explore more in the docs.