Phoenix LiveView is a powerful tool for building real-time web applications. One common feature in search interfaces is updating the query string in the URL as the user types, making the search state shareable and persistent across page reloads.

In this post, we’ll walk through how to append the search query to the URL dynamically in a LiveView-powered search form.

Setting up the search form

First, let’s create a simple search form in our LiveView template. We use phx-change to trigger an event whenever the user types in the search box:

<form phx-change="update_search">
  <input type="text" name="q" value={@query} placeholder="Search" />
</form>

Handling the input change event

Next, in our LiveView module, we handle the event and update the query string in the URL using push_patch/2:

def handle_event("update_search", %{"query" => query}, socket) do
  {:noreply,
   socket
   |> push_patch(to: ~p"/search?query=" <> URI.encode(query))}
end

This ensures that every time the user types, the query string is updated in the browser URL without a full page reload.

Loading the query from the URL

To ensure the LiveView initializes correctly with the query from the URL, we update the handle_params/3 function:

def handle_params(params, _session, socket) do
  query = Map.get(params, "query", "")
  {:ok, assign(socket, query: query)}
end

This makes the search state persistent even when the page is refreshed or the URL is shared.

Full example

defmodule MyAppWeb.SearchLive do
  use MyAppWeb, :live_view

  def render(assigns) do
    ~H"""
    <form phx-change="update_search">
      <input type="text" name="q" value={@query} placeholder="Search" />
    </form>
    """
  end

  def handle_params(params, _session, socket) do
    query = Map.get(params, "query", "")
    {:noreply, assign(socket, query: query)}
  end

  def handle_event("update_search", %{"q" => query}, socket) do
    {:noreply,
     socket
     |> push_patch(to: ~p"/?query=" <> URI.encode(query))}
  end
end

Why use push_patch/2?

Using push_patch/2 ensures:

  • No full page reload: The URL updates dynamically without losing the LiveView state.
  • Bookmarkable search: Users can refresh or share the URL with their search query intact.
  • Improved UX: The search query updates smoothly without disrupting the user experience.

Conclusion

With just a few lines of code, we’ve created a LiveView search form that updates the query string dynamically while typing. This technique keeps the search experience seamless and user-friendly while maintaining state persistence.