ppff01
DaisyUI modal in phoenix 1.8 - code example
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.
Trending in Discussions
Other Trending Topics
Latest Phoenix Threads
Chat & Discussions>Discussions
Latest on Elixir Forum
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 10 of 16 Posts
ppff01
Update: the issue with this implementation is that if you use it with a form for example, the liveview updates will rewrite the html without the
opentag on thedialogHTML element, therefore closing the modal.So here is my final solution: ditch the hook and just include the
opentag from the start.joshua-bouv
Only available in LV 1.1+, but alternatively I believe you can use phx-mounted={JS.ignore_attributes([“open”]}).
It’s a shame the modal got removed from the core_components. I wonder if its because of this and they wanted to keep the components simple?
LostKobrakai
core_components only include what phoenix generators use. Modals in generated code eventually got replaced with separate pages, so there was no use for the modal anymore.
ppff01
Very interesting! Thank you. I checked the doc and the example is actually given on a
dialoggarrison
Which is a fantastic change, the modal abuse in the templates was a bit much
It seems like no matter what anyone says people expect the core components to be a full component system. Hopefully some of the various actual component systems from the community become mature enough to be strongly recommended to new users. I believe Ash has one of those component libraries in their generators now (don’t remember which).
xir
Yesterday I was also testing Phoenix 1.8 + the DaisyUI modal and actually gave up on
showModal()and such, being confused by conflicts between what I made and the flash component, which I had also earlier modified using JS hooks to make it disappear after a certain period of time.So, I went with this purely LiveView solution – good or not. Please criticize.
and
xir
Yesterday, I’m afraid I wasn’t clear enough. I wanted to ask if it’s really that bad to go with a purely LiveView solution without using any JavaScript, like what I did above.
garrison
It’s fine. If you want you can combine events with local JS commands to get lower latency for the open/close. But there are legitimate circumstances in which you actually want the modal to be server-rendered. As an example, I have a piece of UI which supports an arbitrary number of stateful modals, some of which can even fetch web content and hold it in-process. This is obviously not something that can be implemented with local JS commands (or even React, interestingly).
If the latency is bothering you then you can simply render the modal into the page and toggle it with JS. There are no rules here, it’s just preference.
xir
Thank you, @garrison !
RodolfoSilva
This is my implementation:
Requires the LiveView > v1.1.5.