Liveview blowing up Alpine state?

This is vaguely similar to what I’m experiencing. Here’s a minimal project that reproduces the issue. I’d be grateful if anyone can take a look. :pray:

The issue is that when
A) rendering directly from a LiveView, everything works. But when
B) the rendering is moved to a LiveComponent, Alpine’s x-show (or something else) “breaks”: the search results still show, but not immediately on typing (only after users also presses the Enter key).

In other words, moving the render/1 shown below (as well as some few handle_event/3) from

  • A) a :live_view to
  • B) a :live_component

somehow breaks and Alpine’s x-show doesn’t show the <ul> immediately. It does show up but only if one also then presses say the Enter key, or defocuses-and-refocuses the search <input> with a mouse, etc.

def render_from_live_view(assigns) do
  ~H"""
  <div class="flex-col relative" x-data="{open: false}">
    <p>Using LiveView, the result will immediately show below, without needing to also press Enter key.</p>
    <form id="search-form" phx-submit="submit">
      <input
        placeholder="type 'a'"
        name="search-input"
        id="search-input"
        class="block border border-black"
        phx-change="search"
        phx-hook="FocusOnMounted"
        x-on:focus="open = true"
      />
    </form>
    <ul :if={@search_results != []} x-show="open">
      <li :for={result <- @search_results}><%= result %></li>
    </ul>
  </div>
  """
end

And the relevant lines from app.js:

import Alpine from "alpinejs"
window.Alpine = Alpine
Alpine.start()

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {
  params: {_csrf_token: csrfToken},
  hooks: {
    FocusOnMounted: {
      mounted() {
        this.el.focus();
      }
    },
  },
  dom: {
    onBeforeElUpdated(from, to) {
      if (from._x_dataStack) {
        window.Alpine.clone(from, to);
      }
    }
  }
})

Visually, I only see the following differences in the relevant HTML between the :live_view (left) and the :live_component (right):

Other somewhat related threads: