Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~26 min· topic 6 of 7

Topic 2.6

Built-in Interactive Elements

In one line

details/summary give you an open-and-close section, dialog gives you a real popup window, and the popover attribute makes menus and tips that appear on top; all with keyboard support and accessibility built in, often with no JavaScript.

Think of it like this

Furniture that comes with its own hinges. A cupboard door (details) opens and closes when you pull the handle. A pop-up shop window (dialog) is a counter that opens in front of everything; while it's open you deal only with it, and you close it when done. A sticky note (popover) you put on top of your work and flick away with a tap anywhere else. You don't build the hinges; they come with the furniture.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Disclosure widget
A control that shows or hides content when you activate it, like details.
summary
The always-visible label of a details element; clicking it opens or closes the rest.
Modal
A popup that blocks the rest of the page until it's closed.
Non-modal
A popup that leaves the rest of the page usable.
Top layer
A special layer drawn above the whole page, used by modal dialogs and popovers. No z-index can cover it.
Inert
Can't be clicked, focused or read by assistive tech. The page behind a modal dialog is inert.
Light dismiss
Closing a popover by clicking outside it or pressing Escape.
Keyboard focus
Which element receives keys right now; Tab moves it. Focused elements usually show an outline.
::backdrop
A CSS pseudo-element: the layer drawn behind a modal dialog or popover, over the rest of the page.

Step by step

01Make an FAQ with details

Each question is a summary; the answer follows it. The browser draws a triangle marker and handles mouse, keyboard and screen readers (announced as a button that is collapsed or expanded).

index.htmlwhole filehtml
<details>
  <summary>Is Hectal free?</summary>
  <p>Yes, every course is free.</p>
</details>
<details open>
  <summary>Do I need to install anything?</summary>
  <p>No, examples run in your browser.</p>
</details>

02Turn it into an accordion

Give the details the same name. Now only one can be open at a time.

index.htmlwhole filehtml
<details name="faq" open><summary>Question 1</summary><p>Answer 1</p></details>
<details name="faq"><summary>Question 2</summary><p>Answer 2</p></details>

03Open a modal dialog

A modal needs one line of JavaScript: showModal(). Everything else (top layer, backdrop, inert page, Escape, focus moving in) is the browser's work. The form with method="dialog" closes it and reports which button was pressed.

index.htmlwhole filehtml
<button id="del">Delete file</button>
<dialog id="ask">
  <form method="dialog">
    <p>Delete this file?</p>
    <button value="cancel">Cancel</button>
    <button value="yes">Delete</button>
  </form>
</dialog>
<script>
  const ask = document.getElementById("ask");
  document.getElementById("del").onclick = () => ask.showModal();
  ask.onclose = () => console.log(ask.returnValue);
</script>
Open a modal dialogdiagram
Rendering diagram…

04Make a popover with no JavaScript

Put popover on the element and popovertarget on a button pointing at its id. The button toggles it; clicking anywhere else closes it.

index.htmlwhole filehtml
<button popovertarget="menu">Menu</button>
<div id="menu" popover>
  <a href="/">Home</a><br>
  <a href="/html">HTML course</a>
</div>

05Style the open states

CSS can style each state: details[open], dialog::backdrop, [popover]:popover-open, and dialog:modal for a modal dialog. You'll learn these selectors in the CSS course.

style.csswhole filecss
details[open] summary { font-weight: bold; }
dialog::backdrop { background: rgb(0 0 0 / 0.5); }
[popover] { border-radius: 8px; }

06Choose the right one

Use the decision flow below. If none fits, you may need a custom widget, which is much more work to make accessible.

Choose the right onediagram
Rendering diagram…

Try it yourself

  1. 1

    Make the FAQ non-exclusive

    In the first example, predict the second console line if you remove both name="faq" attributes. Run it: After opening the second: true true. Both can be open now.

  2. 2

    Try the modal's keyboard behaviour

    In the dialog example, click Delete file, then press Tab several times. Focus cycles inside the dialog and never reaches the page behind. Press Escape: the console logs Closed with: followed by the last return value, because Escape doesn't change it.

  3. 3

    Make the popover manual

    In the popover example, change popover to popover="manual". Predict the last console line, then run. Open the menu and click outside: it stays open. Click the button again to close it.

Code & diagrams

details and summary: an FAQ accordion Baseline 2024+ New tab

Same name, so opening the second closed the first. The toggle event arrives a moment later (it is queued, not fired instantly). Click the summaries yourself too.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Start: true false
After opening the second: false true
toggle event, second is open: true
A modal dialog with a dialog form New tab

The script opens and closes it once to show the API. Click Delete file to open it yourself: try Escape, Cancel and Delete.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

open: true | modal: true
open after close: false
Closed with: cancel
A popover menu with no JavaScript Baseline 2024+ New tab

Click the button to open it, then click outside or press Escape to dismiss it (light dismiss).

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Shown at start: false
After showPopover: true
Popover type: auto

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use show() when you need a modal

In the dialog example, replace dlg.showModal() in the click handler with dlg.show(), then click Delete file and press Escape or Tab.

terminal
$ the page shows
── what you'll see ──
The dialog appears without a backdrop, Escape does nothing, and Tab moves focus out to the page behind.

Break #2

Call showModal on a dialog that is already open

Add the open attribute to the <dialog> in the HTML and keep the dlg.showModal() line in the script.

terminal
$ Console
── what you'll see ──
Uncaught InvalidStateError: Failed to execute 'showModal' on 'HTMLDialogElement': The dialog is already open as a non-modal dialog, and therefore cannot be opened as a modal one.

Myth vs fact

Myth

You need a JavaScript library for accordions, modals and dropdown menus.

Fact

details, dialog and popover cover the common cases natively, including keyboard and screen-reader behaviour.

Myth

Adding the open attribute to a dialog makes it modal.

Fact

The open attribute opens it non-modally. Only showModal() makes it modal with a backdrop, inert page and Escape handling.

Myth

A popover is the same as a modal dialog.

Fact

A popover doesn't make the page inert and is meant to be dismissed lightly. Use a modal dialog when the user must respond.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The top layer sits outside the normal stacking contexts, so overflow: hidden on an ancestor and z-index wars can't clip or cover a modal dialog or popover. This is the main reason to prefer them over absolutely positioned divs.

  • ▸

    Inside a modal, the browser sets the rest of the document inert. Modal dialogs also get the implicit aria-modal="true". Initial focus goes to the element with autofocus, or else the first focusable element; for long text, consider focusing the dialog itself.

  • ▸

    Exclusive accordions (details name) became Baseline in 2024. Newer additions such as hidden="until-found" (content that find-in-page can reveal) and the ::details-content pseudo-element (to style or animate the hidden part) are not in every browser yet; check support before relying on them.

  • ▸

    popover and dialog combine with CSS anchor positioning to place menus next to their buttons without JavaScript; anchor positioning is new, so check current support before depending on it. The newer Invoker Commands API (commandfor and command attributes on buttons) can open dialogs without JavaScript where supported.

Remember this

  1. 1

    **<details> and <summary>.** details is a box that can be open or closed (a disclosure widget). Its first child summary is the always-visible label; clicking it, or pressing Enter or Space when it has keyboard focus, toggles the rest. The open attribute is present when it's open; write <details open> to start open. The browser fires a toggle event each time it changes.

  2. 2

    Several details with the same **name attribute form an exclusive accordion**: opening one closes the others, with no JavaScript. Content inside a closed details is still found by the browser's find-in-page (Ctrl+F) in Chromium-based browsers, which opens it automatically.

  3. 3

    **<dialog>** is a popup box. Opened with the open attribute or dialog.show(), it's non-modal: the rest of the page still works. Opened with dialog.showModal(), it's modal: it appears in the top layer (above everything, whatever the z-index), the page behind becomes inert (can't be clicked or focused), a ::backdrop covers the page, keyboard focus moves into the dialog, and Escape closes it. Close it with dialog.close(value), which sets returnValue and fires a close event.

  4. 4

    A <form method="dialog"> inside a dialog closes the dialog when submitted, without sending anything to a server, and sets returnValue to the value of the button that was pressed. That's the simplest way to build "OK / Cancel" confirmations.

  5. 5

    **The popover attribute** turns any element into a popover: hidden until shown, then displayed in the top layer. A <button popovertarget="id"> toggles it with no JavaScript. With popover (or popover="auto") it has light dismiss: clicking outside or pressing Escape closes it, and opening another auto popover closes the first. popover="manual" stays until you close it. JavaScript can call showPopover(), hidePopover() and togglePopover().

  6. 6

    When to use which: details for show/hide content in the page (FAQs, "more options"). A modal dialog when the user must deal with something before continuing (confirm a delete, sign in). popover for light, non-blocking layers (menus, tooltips, toasts). Using these instead of hand-made div popups gives you correct keyboard handling, focus management and screen-reader roles for free; you'll add behaviour with JavaScript in the JavaScript course (/javascript).

Explain it without notes

01

What does showModal() give you that show() doesn't?

02

How does <form method="dialog"> work?

03

What is light dismiss, and which kind of popover has it?

04

Why are native details, dialog and popover better than hand-built div widgets?

Practice

01

Build a two-question FAQ where only one answer can be open at a time and the first is open at the start.

02

Build a "Subscribe?" modal with Yes/No buttons that logs the choice when it closes. Open it from a button.

03

Make a button that toggles a small help popover with the text "Passwords need 12 characters".

Trade-offs

  • ↔

    Native elements bring behaviour you can't fully change (the details marker, the dialog's focus rules); usually that's a feature, but highly custom designs need more CSS work.

  • ↔

    Modals interrupt the user; use them only when an answer is needed now. A details section or an inline message is often kinder.

Done when you can

  • I can build a disclosure and an exclusive accordion with details and summary.

  • I can open a modal with showModal() and close it with form method="dialog".

  • I can read returnValue in the close event.

  • I can make a popover with popover and popovertarget, and explain auto vs manual.

  • I can choose between details, dialog and popover for a given need.