Promise-based programmatic dialogs. No HTML boilerplate — created on-demand via JavaScript.
Uso básico
All dialog functions return Promises, so you can use async/await for clean, synchronous-looking code:
// Confirm dialog
const confirmed = await PureAdmin.confirm({
title: 'Delete Item?',
message: 'This action cannot be undone.',
variant: 'danger'
});
if (confirmed) {
// User clicked OK
}
// Alert dialog
await PureAdmin.alert({
title: 'Success!',
message: 'Your changes have been saved.',
variant: 'success'
});
// Prompt dialog
const name = await PureAdmin.prompt({
title: 'Enter Name',
message: 'Please enter your name:',
defaultValue: 'John Doe'
});
if (name !== null) {
console.log('User entered:', name);
}
Diálogos de confirmación
Two-button dialogs that return true (confirmed) or false (cancelled).
Opciones de posición
Dialogs can be positioned in the center (default) or at the top of the viewport.
// Center position (default)
await PureAdmin.alert({
title: 'Centered',
message: 'This dialog is centered.',
position: 'center' // default
});
// Top position
await PureAdmin.prompt({
title: 'Top Position',
message: 'This dialog appears near the top.',
position: 'top'
});
Diálogos de alerta
Single-button dialogs for notifications. Just wait for the user to acknowledge.
Diálogos de solicitud
Text input dialogs that return the entered value (or null if cancelled).
Diálogos secuenciales
Chain multiple dialogs together using async/await:
async function sequentialDialogs() {
const name = await PureAdmin.prompt({
title: 'Step 1 of 3',
message: 'Enter your name:'
});
if (name === null) return;
const email = await PureAdmin.prompt({
title: 'Step 2 of 3',
message: 'Enter your email:'
});
if (email === null) return;
const confirmed = await PureAdmin.confirm({
title: 'Step 3 of 3',
message: `Confirm: ${name} <${email}>`,
variant: 'success'
});
if (confirmed) {
await PureAdmin.alert({
title: 'Complete!',
message: 'Registration successful.',
variant: 'success'
});
}
}
Integración de LiveView
Use onclick with liveSocket to push results back to the server.
The server records the outcome and pushes a toast straight back — try the buttons:
Client — push the result to the server:
// Push a dialog result to LiveView from plain JS (outside a hook).
async function confirmAndPush(action) {
const confirmed = await PureAdmin.confirm({
title: 'Delete Item?',
message: 'This action cannot be undone.',
variant: 'danger'
});
if (confirmed) {
// Use the public execJS API with the same encoded command phx-click uses.
// `value` becomes the event params on the server.
const el = document.querySelector('[data-phx-main]');
window.liveSocket.execJS(el, JSON.stringify(
[["push", { event: "dialog_result", value: { action, result: "confirmed" } }]]
));
}
}
Servidor — reply with a toast, no reload:
# The LiveView receives the pushed event and sends a toast back — no reload,
# the PureAdminToast hook just renders it wherever the user is.
def handle_event("dialog_result", %{"action" => action, "result" => result}, socket) do
{:noreply,
socket
|> assign(last_result: "#{action}: #{result}")
|> push_toast("success", "Server received your action",
"You just performed #{action} (#{result}) in the dialog.")}
end
Server-Initiated Dialog
The opposite direction, and a first-class keen feature: the button below is a
real phx-click that hits the server first. The server opens a
server-rendered dialog with PureAdmin.Dialog.confirm/2; each button is an ordinary event, so the
user's choice arrives as a normal handle_event and the dialog auto-closes — no client bridge, no
promise plumbing. Every outcome pushes a toast back from the server, and the ✕/backdrop/Escape
dismiss is a first-class event too (on_dismiss), so nothing closes silently. Classic use:
"this document was changed by someone else."
Pick a button, or dismiss with ✕ / click-outside / Escape — each pushes a different toast.
# 1. Setup once. on_mount seeds :pa_dialog + auto-close; the host renders it.
live_session :default, on_mount: [{PureAdmin.Dialog, :default}] do
# ...your live routes...
end
# app.html.heex, mounted once:
# <PureAdmin.Dialog.host dialog={@pa_dialog} />
# 2. A real phx-click handler opens the dialog FROM THE SERVER. `on_dismiss`
# makes the ✕/backdrop/Esc dismiss a first-class event too.
def handle_event("simulate_external_edit", _params, socket) do
{:noreply,
PureAdmin.Dialog.confirm(socket,
title: "Document changed",
message: "Someone else updated this document. Reload their version?",
variant: "warning", banded: true, position: :top,
confirm: [label: "Reload theirs", variant: "warning", event: "doc_reload"],
cancel: [label: "Keep mine", event: "doc_keep"],
on_dismiss: "doc_dismiss"
)}
end
# 3. Every outcome is an ORDINARY event; the dialog auto-closes. Push a toast
# straight back from the server (PureAdmin.Components.Toast.push_toast/4).
def handle_event("doc_reload", _p, socket), do:
{:noreply, push_toast(socket, "warning", "Document reloaded", "Server version loaded.")}
def handle_event("doc_keep", _p, socket), do:
{:noreply, push_toast(socket, "success", "Kept your version", "Local changes preserved.")}
def handle_event("doc_dismiss", _p, socket), do: # ✕ / backdrop / Escape
{:noreply, push_toast(socket, "info", "Dialog dismissed", "Nothing was changed.")}
Custom / Form Dialog
Standard dialogs can't express an arbitrary form, so PureAdmin.Dialog.open/3 just stashes a keyed
spec and you render your own <.modal> with a real LiveView form — full
phx-change validation and phx-submit. close/1 dismisses it. The server
opens it the same way (a phx-click handler), but owns the content.
# Custom/form dialog (requirement B): open/3 stashes a keyed spec — YOU render
# your own <.modal> with a real LiveView form. close/1 dismisses it.
def handle_event("edit_profile", _p, socket) do
form = to_form(%{"name" => "Ada Lovelace", "email" => "ada@example.com"}, as: :profile)
{:noreply, socket |> assign(profile_form: form) |> PureAdmin.Dialog.open(:edit_profile)}
end
def handle_event("validate_profile", %{"profile" => params}, socket) do
{:noreply, assign(socket, profile_form: to_form(params, as: :profile, errors: errors(params)))}
end
def handle_event("save_profile", %{"profile" => params}, socket) do
case errors(params) do
[] -> {:noreply, socket |> PureAdmin.Dialog.close() |> assign(profile_result: "Saved.")}
errs -> {:noreply, assign(socket, profile_form: to_form(params, as: :profile, errors: errs))}
end
end
# render — your OWN modal + form, keyed on @pa_dialog:
<.modal :if={@pa_dialog && @pa_dialog.key == :edit_profile} id="edit-profile" show
title_text="Edit profile" on_cancel={JS.push("pa-dialog:close")}>
<.form for={@profile_form} class="pa-form"
phx-change="validate_profile" phx-submit="save_profile">
<div class="pa-form-group"><label>Name</label><.input field={@profile_form[:name]} /></div>
<div class="pa-form-group"><label>Email</label><.input field={@profile_form[:email]} type="email" /></div>
<div class="pa-modal__footer">
<button type="button" class="pa-btn pa-btn--secondary" phx-click="pa-dialog:close">Cancel</button>
<button type="submit" class="pa-btn pa-btn--primary">Save</button>
</div>
</.form>
</.modal>
Referencia de la API
PureAdmin.confirm(options)
Returns Promise<boolean>
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
title
| string | 'Confirm' | Dialog title |
message
| string | 'Are you sure?' | Dialog message |
confirmText
| string | 'OK' | Confirm button text |
cancelText
| string | 'Cancel' | Cancel button text |
variant
| string | 'primary' | Header theme: primary, success, warning, danger |
confirmVariant
| string | (same as variant) | Confirm button style |
size
| string | 'sm' | Modal size: sm, md, lg, xl |
position
| string | 'center' | Vertical position: center, top |
closeOnBackdrop
| boolean | true | Close when clicking outside |
PureAdmin.alert(options)
Returns Promise<void>
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
title
| string | 'Alert' | Dialog title |
message
| string | '' | Dialog message |
okText
| string | 'OK' | Button text |
variant
| string | 'primary' | Header and button theme |
size
| string | 'sm' | Modal size |
position
| string | 'center' | Vertical position: center, top |
PureAdmin.prompt(options)
Returns Promise<string | null>
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
title
| string | 'Input' | Dialog title |
message
| string | 'Enter value:' | Dialog message |
defaultValue
| string | '' | Initial input value |
placeholder
| string | '' | Input placeholder |
confirmText
| string | 'OK' | Confirm button text |
cancelText
| string | 'Cancel' | Cancel button text |
validator
| function | null | Validation: (value) => true | string |
variant
| string | 'primary' | Header theme |
size
| string | 'sm' | Modal size |
position
| string | 'center' | Vertical position: center, top |