Hi there,
I’ve been testing Phoenix 1.8 a lot lately and noticed the modal component from 1.7 had disappeared. Since we now have DaisyUI which comes with a Modal component, I figured I’d try to use it. It’s not that easy because if you want to do it the cleanest way, you need to use the browser’s showModal() function. I won’t get into too much detail but after several hours of tests here is what I came up with. I hope it can be useful to some of you here!
The component:
@doc """
Modal dialog.
"""
attr :id, :string, required: true
attr :on_cancel, JS, default: %JS{}
slot :inner_block, required: true
def modal(assigns) do
~H"""
<dialog
id={@id}
phx-hook="Modal"
phx-remove={
JS.remove_attribute("open")
|> JS.transition({"ease-out duration-200", "opacity-100", "opacity-0"}, time: 0)
}
data-cancel={JS.exec(@on_cancel, "phx-remove")}
class="modal"
>
<.focus_wrap
id={"#{@id}-container"}
phx-window-keydown={JS.exec("data-cancel", to: "##{@id}")}
phx-key="escape"
phx-click-away={JS.exec("data-cancel", to: "##{@id}")}
class="modal-box"
>
<.button phx-click={JS.exec("data-cancel", to: "##{@id}")} class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2 tx-lg">✕</.button>
<%= render_slot(@inner_block) %>
</.focus_wrap>
</dialog>
"""
end
Add a new hook which will trigger showModal():
Hooks.Modal = {
mounted() {
this.el.showModal();
},
}
In your liveview, just add the modal:
<.modal
id="delete_modal"
:if={@live_action in [:delete]}
on_cancel={JS.patch(~p"/brands")}
>
<h3 class="text-xl text-bold">Warning</h3>
<p class="text-md mt-3">Are you sure you want to delete brand {@brand.name}?</p>
<div class="modal-action">
<.button phx-click="delete" phx-value-id={@brand.id}>Delete</.button>
</div>
</.modal>
It’s basically a hot-swap solution for Phoenix modal 1.7. Please note that the modal should be opened only with a specific live_action which is defined in the router:
live "/brands/:id/delete", BrandsLive, :delete
This is necessary because we don’t have an easy way to trigger the close javascript command and retrieve data while letting the browser-operated fade out operate properly (or at least I didn’t find one). But it’s also very useful because it allows us to pass parameters to the modal easily using the url.
Anyway, just my two cents! Feel free to suggest improvements or ask questions.






















