# `Xenia.Persistent`
[🔗](https://github.com/uzaydurdu/xenia/blob/v0.1.1/lib/xenia/app/persistent.ex#L1)

A layout's persistent part: a LiveView that stays mounted, with its state
and its JavaScript components, while the user moves between the pages
under its layout. It lives in a `persistent.ex` next to the `layout.ex`;
the module name is yours.

```elixir
# app/(auth)/persistent.ex, next to app/(auth)/layout.ex
defmodule MyAppWeb.ShellLive do
  use MyAppWeb, :live_view
  use Xenia.Persistent

  def mount(_params, _session, socket), do: {:ok, assign(socket, path: nil)}

  def handle_navigation(uri, socket) do
    {:noreply, assign(socket, path: URI.parse(uri).path)}
  end

  def render(assigns) do
    ~H"""
    <nav>
      <.link navigate="/dashboard" class={@path == "/dashboard" && "active"}>Dashboard</.link>
    </nav>
    """
  end
end
```

Xenia renders it as a sticky LiveView, from the page, at the place its
layout's frame puts `@persistent` (CLAUDE.md §9, experiment S1). What that
means for you:

  * **It knows the current page through `handle_navigation/2`.** A sticky
    LiveView can't define `handle_params/3`: LiveView raises. Xenia calls
    `handle_navigation(uri, socket)` once it is connected, and after every
    navigation and patch, from LiveView's `phx:navigate` browser event.
  * **It is configured once.** It mounts when the first page under its
    layout renders, and keeps its state until a page outside the layout is
    shown. Pages can't pass it new parameters; send it a message instead.
  * **It only persists within one `live_session`.** Leaving it is a full
    page load.

# `handle_navigation`
*optional* 

```elixir
@callback handle_navigation(uri :: String.t(), socket :: Phoenix.LiveView.Socket.t()) ::
  {:noreply, Phoenix.LiveView.Socket.t()}
```

Called with the page's full URL once the persistent part is connected,
and after every navigation and patch. Optional.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
