I have a button like this:
<.button phx-click="delete-everything" phx-disable-with="Please wait...">
Delete Everything
</.button>
and I want to gracefully handle “accidental” clicks.
So I have this very simple way to “confirm user action” that I will share.
First, add this JS to app.js:
import ultraConfirm from "./ultraConfirm";
window.addEventListener("ultra-confirm", ultraConfirm.confirmAndExec);
Then create a file ultraConfirm.js beside app.js with this code:
const execAttr = (el, attrName) => {
const attr = el.getAttribute(attrName);
attr && liveSocket.execJS(el, attr);
};
const confirmAndExec = ({ detail, srcElement }) => {
const { message } = detail;
if (confirm(message || "Are you sure?")) {
execAttr(srcElement, "phx-ultra-confirm-ok");
} else {
execAttr(srcElement, "phx-ultra-confirm-cancel");
}
};
export default { confirmAndExec };
You can see this is using Javascript’s confirm, which is like alert except the user can OK or Cancel.
Now all I need to do is rewrite my button like this:
<.button
phx-click={
JS.dispatch("ultra-confirm",
detail: %{message: "Are you sure you want to delete everything?"}
)
}
phx-ultra-confirm-ok={JS.push("delete-everything")}
phx-disable-with="Please wait..."
>
Delete Everything
</.button>
You can send a payload (what is usually called params in the handle_event/3 callback) with the JS.push call. Just check the docs for that function (Phoenix.LiveView.JS — Phoenix LiveView v0.20.17).
Note that I named the attribute phx-ultra-confirm-ok. I did this because if I named it, e.g. ultra-confirm-ok then core components like button will complain about “unexpected attribute”.
Note finally that the phx-disable-with works as we would expect it too.






















