Recipes
Open a dialog from a menu item
Confirm something chosen from a menu, without the dialog closing when the menu does.
View as Markdown for coding assistants, or see llms.txt.
Control the dialog with state, put it next to the menu (not inside it) and open it from the menu item's onClick.
Choose Delete… to confirm.
"use client";
import { Button } from "@azmr/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@azmr/ui/menu";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@azmr/ui/modal";
import { useState } from "react";
// Open a dialog from a menu item: control the dialog and open it from the item's onClick. The
// dialog sits next to the menu, not inside it, so it survives the menu closing.
export default function MenuOpensDialog() {
const [confirming, setConfirming] = useState(false);
const [deleted, setDeleted] = useState(false);
return (
<div className="flex items-center gap-4">
<DropdownMenu>
<DropdownMenuTrigger render={<Button variant="outline">More</Button>} />
<DropdownMenuContent>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuItem variant="destructive" onClick={() => setConfirming(true)}>
Delete…
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<AlertDialog open={confirming} onOpenChange={setConfirming}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete this item?</AlertDialogTitle>
<AlertDialogDescription>This cannot be undone.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Keep it</AlertDialogCancel>
<AlertDialogAction onClick={() => setDeleted(true)}>Delete</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<p className="text-sm text-muted-foreground" aria-live="polite">
{deleted ? "Deleted." : "Choose Delete… to confirm."}
</p>
</div>
);
}Why it is built this way
A menu closes as soon as an item is chosen, and everything inside it goes with it. A dialog placed inside the menu would be removed in the same moment it opened. Keeping the dialog as a sibling, with open held in your own state, means it is still there when the menu closes.
- The
AlertDialogstarts focus on its cancel button, so Enter does not confirm by reflex. - Focus returns to the control that opened it when the dialog closes.
- Name what is being changed in the title, because the person has just left the row it belonged to.
A longer version, with a list, an Undo toast and focus moved after the row is removed, is the confirm-delete flow.