The dialog element: modals you stop maintaining
The accessible-modal checklist is long and unforgiving: trap focus inside, restore focus on close, handle Escape, mark the background inert, stack above everything, announce correctly to screen readers. Every hand-rolled modal ships bugs against that list—usually the focus ones, which only keyboard and screen-reader users hit.
<dialog> ships the checklist in the browser. One element, one method:
<dialog id="confirm" closedby="any">
<h2>Delete this post?</h2>
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="confirm">Delete</button>
</form>
</dialog>
// modal mode: focus trap + inert page + top layer
confirm.showModal();showModal() is the important call: it puts the dialog in the top layer, makes the rest of the page genuinely inert, traps Tab, and wires Escape. closedby="any" adds light-dismiss—click the backdrop, dialog closes—without a click-outside listener. And method="dialog" forms close the dialog and report which button was pressed via returnValue, no handlers required.
“Every hand-rolled focus trap is a bug report from a keyboard user you have not met yet.”
The styling story
::backdrop styles the scrim directly—blur it, tint it, animate it. Entry animations use the same @starting-style pattern as popovers, so dialogs can scale-and-fade in with pure CSS. The decision tree is short now: interruptive flows get dialog.showModal(); passive overlays get popover; and the modal library gets deleted.