Overlays

ConfirmButton

A button that asks first, in a dialog on the page, then submits its form, follows its link or calls back.

#forms#button#dialog#interactive

Demo

Preview
Submits its form on yes (here, reloading this page).
Not archived.

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/confirm_button.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/confirm_button.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/confirm_button.qwe
component ConfirmButtonDemoLive() {    state archived = false    <div.demo-row>        <ConfirmButton message="Archive this project? You can bring it back later." tone="accent" variant="soft"                       ok="Archive" on_confirm={() => { archived = true }}>Archive</ConfirmButton>        <span.demo-note>{archived ? "Archived." : "Not archived."}</span>    </div>}view ConfirmButtonDemo() =    <div.demo-stack>        <form.demo-row method="get" action="#confirm_button">            <ConfirmButton title="Delete project?" message="This deletes the project and all its files. It cannot be undone."                           ok="Delete" name="deleted" value="yes">Delete project</ConfirmButton>            <span.demo-note>Submits its form on yes (here, reloading this page).</span>        </form>        <div.demo-row>            <ConfirmButton href="#confirm_button" message="Leave this page?" tone="neutral" variant="outline" ok="Leave">                A link            </ConfirmButton>        </div>        <ConfirmButtonDemoLive/>    </div>

Source

ui/confirm_button.qwe
// ConfirmButton: a button that asks "are you sure?" before it acts, in a// dialog on the page (the builtin `ask`). On yes it does what it would have// done: submits its form, follows its link, or calls on_confirm().////   <form method="post" action="/projects/7/delete">//       <ConfirmButton message="This deletes the project and its files.">Delete project</ConfirmButton>//   </form>//   <ConfirmButton href="/logout" tone="accent" message="Sign out on this device?" ok="Sign out">Sign out</ConfirmButton>//// message: the question. title: a heading over it. ok ("Confirm") and cancel// ("Cancel"): the dialog's buttons. tone: "danger" (default: the dialog starts// on Cancel), "accent" or "neutral", for the button and the dialog.// In a form, on yes it submits the form with this button as the submitter, so// its name and value are sent. href: a link instead. on_confirm(): inside one// of your components, what yes does (then nothing is submitted).// variant: "solid" (default), "soft", "outline" or "ghost"; size: "sm", "md" or// "lg". It is styled as a Button when button_css is on the page.// confirm_button_css also styles `ask`'s dialog (its q- classes), at the lowest// specificity, so the page's own styles for it (or the Notices') win.import ui/theme.qwe use ui_clslet confirm_button_css = css`:where(.q-backdrop) {  position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 16px;  background: var(--ui-overlay); opacity: 0; transition: opacity .15s;}:where(.q-backdrop.q-open) { opacity: 1; }:where(.q-dialog) {  box-sizing: border-box; width: min(420px, 100%); padding: 20px 22px; border: 1px solid var(--ui-border);  border-radius: var(--ui-radius); background: var(--ui-surface); color: var(--ui-fg); box-shadow: var(--ui-shadow-lg);  font: 15px/1.5 var(--ui-font); transform: translateY(8px) scale(.98); transition: transform .15s;}:where(.q-open .q-dialog) { transform: none; }:where(.q-dialog .q-title) { margin: 0 0 6px; font-size: 17px; font-weight: 600; line-height: 1.3; }:where(.q-dialog .q-message) { margin: 0 0 20px; color: var(--ui-muted); }:where(.q-dialog .q-actions) { display: flex; justify-content: flex-end; gap: 8px; }:where(.q-dialog .q-actions button) {  height: 36px; padding: 0 14px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm);  background: transparent; color: var(--ui-fg); font: 500 14px/1 var(--ui-font); cursor: pointer;}:where(.q-dialog .q-actions button:hover) { background: var(--ui-subtle); }:where(.q-dialog .q-actions .q-ok) { border-color: transparent; background: var(--ui-accent); color: var(--ui-accent-fg); }:where(.q-dialog.q-danger .q-actions .q-ok) { background: var(--ui-danger); color: #fff; }:where(.q-dialog .q-actions .q-ok:hover) { background: color-mix(in srgb, var(--ui-accent) 88%, var(--ui-fg)); }:where(.q-dialog.q-danger .q-actions .q-ok:hover) { background: color-mix(in srgb, var(--ui-danger) 88%, var(--ui-fg)); }:where(.q-dialog .q-actions button:focus-visible) { outline: none; box-shadow: var(--ui-focus); }@media (prefers-reduced-motion: reduce) { :where(.q-backdrop, .q-dialog) { transition: none; } }`component ConfirmButton(message: str, title: str? = null, ok: str = "Confirm", cancel: str = "Cancel",                        tone: str = "danger", href: str? = null, name: str? = null, value: str? = null,                        variant: str = "solid", size: str = "md", disabled: bool = false, on_confirm = null,                        class: str? = null, children) {    style global confirm_button_css    state el = null    let cls = ui_cls(["ui-btn", `ui-btn-${variant}`, tone != "accent" && `ui-btn-${tone}`,                      size != "md" && `ui-btn-${size}`, "ui-confirm-btn", class])    let go = (e) => {        e.preventDefault()        if ask(message, { title, ok, cancel, tone }) {            if on_confirm != null { on_confirm() }            else if href != null { navigate(href) }            else if el.form != null { el.form.requestSubmit(el) }        }    }    href != null        ? <a class={cls} href={href} aria-disabled={disabled ? "true" : null} aria-haspopup="dialog"             @mount={(a) => { el = a }} @click={go}>{children}</a>        : <button class={cls} type={on_confirm != null ? "button" : "submit"} name={name} value={value}                  disabled={disabled} aria-haspopup="dialog" @mount={(b) => { el = b }} @click={go}>{children}</button>}
Thread
55Useful? Like it, or add to its thread below.

Thread 0 posts

On ConfirmButton: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.