Showing A Yes No Cancel Message Box

Is there a way we can “prompt” the user as in a Yes No Cancel Dialog box?

For example:
Pressing a delete button, you may want to prompt the user to confirm or cancel.

The example in the kitchen sink may be what you are looking for.

Perfect, I keep forgetting about the Kitchen Sink.

Thank you

A quick prompt function that might prove useful to you:

async function prompt(heading, body, buttons=["Cancel", "Ok"], options={title: heading, size: {width: 360, height: 280}}) {
    const [dlgEl, formEl, headingEl, dividerEl, bodyEl, footerEl] = 
        ["dialog", "form", "sp-heading", "sp-divider", "sp-body", "footer"]
        .map(tag => document.createElement(tag));
    [headingEl, dividerEl, bodyEl, footerEl].forEach(el => {
        el.style.margin="6px";
        el.style.width="calc(100% - 12px)";
    });

    formEl.setAttribute("method", "dialog");
    formEl.addEventListener("submit", () => dlgEl.close());

    footerEl.style.marginTop = "26px";

    dividerEl.setAttribute("size", "large");

    headingEl.textContent = heading;

    bodyEl.textContent = body;
    
    buttons.forEach((btnText, idx) => {
        const btnEl = document.createElement("sp-button");
        btnEl.setAttribute("variant", idx === (buttons.length - 1) ? (btnText.variant || "cta") : "secondary");
        if (idx === buttons.length - 1) btnEl.setAttribute("autofocus", "autofocus");
        if (idx < buttons.length - 1) btnEl.setAttribute("quiet");
        btnEl.textContent = (btnText.text || btnText);
        btnEl.style.marginLeft = "12px";
        btnEl.addEventListener("click", () => dlgEl.close((btnText.text || btnText)));
        footerEl.appendChild(btnEl);
    });

    [headingEl, dividerEl, bodyEl, footerEl].forEach(el => formEl.appendChild(el));
    dlgEl.appendChild(formEl);
    document.body.appendChild(dlgEl);

    return dlgEl.uxpShowModal(options);
}

const r = await prompt("Upload Large File", "This is a large file (over 100MB) -- it may take a few moments to upload.", ["Skip", "Upload"]);
if ((r||"Upload") !== "Upload") { /* cancelled or No */ }
else { /* Yes */ }

const r = await prompt("Delete File", "Are you sure you wish to delete this file? This action cannot be undone.", ["Cancel", {variant: "warning", text: "Delete"}]);
if ((r !== "Delete") { /* nope, don't do it! */ }
else { /* Do the delete */ }

3 Likes

That’s great ! :+1:t3: :+1:t3:
Might it be possible to display an image below the divider line for instance?

@kerrishotts I’ve noticed a weird behavior with the dialog’s close() function. I have a dialog with a text-input whose value I want to return, but upon form submit the close() fully ignores the parameters:

formEl.addEventListener("submit", () => (dlgEl as HTMLDialogElement).close(textInput.value));

When I await the dialog function, there’s no return value.

This however…

btnEl.addEventListener("click", () => (dlgEl as HTMLDialogElement).close(textInput.value));

…works correctly, so there must be an issue with the submit event. Maybe there are some internal timing issues and the dialog gets closed before the event callback is executed or something like that?

When I console.log the value inside the submit event callback it’s logging correctly. It simply gets lost on the way through the close-function:

formEl.addEventListener("submit", () => console.log(textInput.value));

Any idea what the problem could be?

I do have an idea!

A form’s default action is to close the dialog it finds itself inside, and it does so with close("").

Since you want to override this behavior, be sure to call the event’s preventDefault method so that your return value doesn’t get modified.

1 Like

Ah, makes sense, I didn’t know about this specific dialog+form behavior.
preventDefault works perfectly, thanks!