Juneum
Elixir, Phoenix, and Javascript

Using alpine.js' x-data attribute in HEEx templates

September 21, 2021
trisager

Phoenix 1.6 (currently available as a release candidate) uses LiveView 0.16, and with it comes a new HTML engine called HEEx. HEEx is HTML-aware, so you will get a compile-time error if your template has errors such as missing closing tags, and it provides a convenient, HTML-like syntax for injecting function components.

One major gotcha with HEEX templates is that you can no longer use the familiar <%= ... %> interpolation syntax with HTML attributes. E.g where you could previously do this:

<div class="<%= @class %>">...</div>

you will now have to do this instead:

<div class={@class}>...</div>

You can still use the <%= ... %> syntax for interpolation in the HTML body.

The new syntax is nice and compact, but we ran into difficulties converting a template that uses Alpine.js to HEEx. In that template we have an enabled/disabled toggle button that we animate with Alpine.js. Before converting to HEEx we could provide the initial value of the toggle dynamically using an @enabled assign, like this:

<div x-data="{ enabled: <%= @enabled %>}">...</div>

Unfortunately, a straight translation to the new syntax doesn't work:

<div x-data="{ enabled: {@enabled} }">...</div>   # This doesn't work

Workaround

After some unsuccessful experiments with alternative (messy) ways of writing this, we eventually gave up and started looking for a workaround. HEEx lets you set multiple dynamic attributes like this:

<div {@dynamic_attrs}>...</div>

where @dynamic_attrs is a keyword list or a map containing key/value pairs for the dynamic attributes, e.g [id: "toggle", class: "enabled"]

Using this approach, we did this in our mount function:

def mount(_params, _session, socket) do
...
{:ok, socket |> assign(dynamic_attrs: [x_data: "{enabled: true}"]
end

In our template we then used the <div {@dynamic_attrs}>...</div> syntax shown above to get the toogle working.

← Back to articles