Kodokon kodokon.com

Modern interactive HTML: dialog, details, popover, contenteditable

Replace your UI libraries with modern HTML's native primitives: modal dialogs, exclusive accordions, popovers and editable regions.

10 min · 3 questions

Open this lesson in Kodokon

<dialog> natively solves what years of modal libraries have hacked together. showModal() projects the element into the top layer - above any z-index -, makes the rest of the document inert (no focus, no clicks) and exposes the ::backdrop pseudo-element. show(), on the other hand, displays a non-modal dialog, with no inertness and no backdrop. The recent closedby=any attribute adds closing by clicking outside.

HTML
<dialog id="confirm-dlg">
  <form method="dialog">
    <p>Delete this item?</p>
    <button value="cancel">Cancel</button>
    <button value="ok">Confirm</button>
  </form>
</dialog>
A method=dialog form closes the dialog without a network request.

A <form method=dialog> closes the dialog without a network submission: the value of the triggering button becomes dialog.returnValue, which the close event lets you read. The Escape key closes a modal dialog by first emitting cancel, which you can cancel with preventDefault() if input is in progress.

JAVASCRIPT
const dlg = document.getElementById("confirm-dlg");
dlg.showModal();
dlg.addEventListener("close", () => {
  console.log(dlg.returnValue); // "ok" or "cancel"
});
Retrieving the user's choice on close.

The Popover API covers menus, rich tooltips and toasts without JavaScript: put popover on the element and popovertarget on a button, and the browser handles the top layer, light dismiss (outside click, Escape) and the mutual closing of auto popovers. Unlike showModal(), a popover does not make the page inert. The beforetoggle and toggle events let you cancel or observe every transition.

HTML
<button popovertarget="user-menu">Menu</button>
<div id="user-menu" popover>
  <button>Profile</button>
  <button>Log out</button>
</div>
A complete menu, without a single line of JavaScript.

<details> provides accessible collapsible content without a script, and a shared name attribute creates an exclusive group: opening one closes the others. The toggle event fires there on every state change. On the editing side, contenteditable turns any element into a rich input area; its plaintext-only variant forbids any markup, and the beforeinput event advantageously replaces the deprecated document.execCommand API.

HTML
<details name="faq" open>
  <summary>Delivery time?</summary>
  <p>Within 48 hours.</p>
</details>
<details name="faq">
  <summary>Return policy?</summary>
  <p>Within 30 days.</p>
</details>
The shared name produces a native exclusive accordion.

Knowledge check

Make sure you remember the key points of this lesson.

  1. What does showModal() bring over show()?
    • It blocks JavaScript execution until the dialog closes
    • It places the dialog in the top layer, makes the rest of the document inert and enables ::backdrop
    • It only prevents the page from scrolling
  2. What does an identical name attribute on several <details> produce?
    • They are submitted together in the parent form
    • Nothing: name is not a valid attribute on details
    • An exclusive accordion: opening one automatically closes the others
  3. What is the behavioral difference between an auto popover and a manual popover?
    • auto gets light dismiss (outside click, Escape) and closes the other auto popovers; manual stays open until it is closed explicitly
    • manual cannot be placed in the top layer
    • auto opens by itself when the page loads