Integrating AlpineJS with Surface

I’m trying to integrate AlpineJS in a LiveView project using Surface. I’ve tried a few different interpolation techniques but none seem to work. Here is some of the trials.

def render(assigns) do
  ~F"""
    <div x-data="{message: 'hello world'}" x-text="message" />
   """
end
def render(assigns) do
  ~F"""
    <div x-data={"{message: 'hello world'}"} x-text="message" />
   """
end
def render(assigns) do
  ~F"""
    <div x-data={
     """
       {message: 'hello world'}\
    """} 
    x-text="message" />
   """
end

But none of these work. Either nothing gets displayed or I get some compilation errors. Anyone had any luck with this?

This sort of thing works:

<div
        x-data="{
              open: false,
              toggle() {
                  if (this.open) { return this.close() }
                  this.open = true
              },
              close(focusAfter) {
                  if (! this.open) return
                  this.open = false
                  focusAfter && focusAfter.focus()
              }
          }"
        x-on:keydown.escape.prevent.stop="close($refs.button)"
        x-on:focusin.window="! $refs.panel.contains($event.target) && close()"
        x-id="['dropdown-button']"
        class="relative"
      >
x-data={"{ on: #{@on} }"}

If you’re using Alpine to change the DOM, you need phx-update="ignore" and an id on the element.

At times you’ll want/need to use opts={"x-some-alpine-thing": "something"} for components.

<ButtonSmall click="reset_to_defaults" color="gray" opts={"x-on:click": "open = false"}>
  Reset to defaults
</ButtonSmall>

Where you have an opts prop

@doc "Additional attributes to add onto the generated element"
prop opts, :keyword, default: []

def render(assigns) do
  ~F"""
  <button ... {...@opts}>
    <#slot />
  </button>
  """
end