Why is HTML state no reset?

After watching Gio Francischelli’s talk at Elixir Conf EU 2025 I was wondering why the HTML state was not reset on the reconnect?

So I am asking you guys if anyone can explain? It is nagging me…
In my head the data-active={tab.name == @initial_tab} should evaluate to true on the reconnect and making the first tab selected.

I have a small reproduction liveview with some hardcoded values here:

defmodule TabTestWeb.TabLive do
  use TabTestWeb, :live_view

  def render(assigns) do
    ~H"""
    <.tabs id="example">
      <:tab name="Movies">
        <ul>
          <li>LOTR</li>
          <li>Hunger Games</li>
        </ul>
      </:tab>

      <:tab name="Songs">
        <ul>
          <li>Get Down</li>
          <li>Yellow Submarine</li>
        </ul>
      </:tab>
    </.tabs>
    """
  end

  def tabs(assigns) do
    assigns = assign_new(assigns, :initial_tab, fn -> "Movies" end)

    ~H"""
    <div id={@id} class="tabs" data-reset={reset()}>
      <button
        :for={{tab, index} <- Enum.with_index(@tab)}
        phx-click={change_tab(@id, index)}
        data-active={tab.name == @initial_tab}
        class="data-active:bg-purple-800"
      >
        {tab.name}
      </button>

      <div :for={tab <- @tab} data-active={tab.name == @initial_tab} class="hidden data-active:block">
        {render_slot(tab)}
      </div>
    </div>
    """
  end

  defp reset, do: JS.remove_attribute("data-active", to: {:inner, "[data-active]"})

  defp change_tab(id, index) do
    JS.exec("data-reset", to: {:closest, ".tabs"})
    |> JS.set_attribute({"data-active", true}, to: "##{id} :nth-of-type(#{index + 1})")
  end
end

I reproduce a disconnect/reconnect in the browser console with liveSocket.disconnect() + liveSocket.connect()

My guess is -
Because initial_tab is not stored on the socket assigns, so the DOM doesn’t change on reconnect.
If you do IO.inspect(assigns.initial_tab) you would still get “Movies” on reconnect. But socket.assigns is not changing, so there is no diff to patch.

I tried this -

def mount(_params, _session, socket) do {:ok, socket |> assign(:initial_tab, “Movies”)} end

In the template

<.tabs id=“example” initial_tab={@initial_tab}>

But still it worked. So I think its working because JS commands are DOM patch aware. Its mentioned in the docs.
I don’t have a concrete answer. Would be glad if anyone can provide more insights.

From the docs -
JS commands are DOM-patch aware, so operations applied by the JS APIs will stick to elements across patches from the server.