Why this deep dive exists
This course has quietly held a line: HTML says what things ARE, and behavior belongs elsewhere. Here is the plot twist - the "elsewhere" has been shrinking. Browsers absorbed the most common interactive patterns into HTML itself, so a growing family of clicks, toggles, and overlays now ships with zero scripts. Every example below runs live in this page's script-free preview panels, which is itself the proof.
details and summary - the disclosure widget core
A disclosure widget is a click-to-reveal: question closed, answer hidden, click, answer shown. You have used it on this very page all course long - every collapsible card here is a <details> element wearing a class="card" outfit. Underneath the styling, the open-close behavior is 100% free HTML.
LiveOne element, zero scripts4 min▶
The recipe: a <details> element whose first child is a <summary> (the always-visible clickable line). Everything after the summary is hidden until the user opens it. Add the open attribute to start expanded. The browser supplies the click handling, the keyboard handling, and the screen-reader announcement ("collapsed" / "expanded") - all of it.
<h3>FAQ</h3> <details open> <summary>Does this need JavaScript?</summary> <p>No. The browser handles the click, the keyboard, and the screen reader.</p> </details> <details> <summary>Can it start open?</summary> <p>Yes - put the open attribute on it, like the first question here.</p> </details>
One distinction worth making: the playground above uses plain, unstyled details - that is the element as taught. The cards on this course page are the same element plus CSS. Same skeleton, different clothes: exactly the HTML-vs-CSS split this course keeps preaching.
GitHub's "show more" sections, MDN's collapsible sidebars, and thousands of documentation FAQs are bare details elements. View source on a GitHub release changelog and you will find them - now you can read exactly what they are.
LiveExclusive accordions with the name attribute3 min▶
Give several details elements the same name value and they become an exclusive accordion: opening one closes the others, like radio buttons for content. This is a recent addition - supported in Chrome and Edge 120+, Safari 17.2+, and Firefox 130+ (so roughly every browser updated since 2024). Older browsers simply ignore name and allow multiple panels open at once - a graceful downgrade, not a breakage.
<details name="faq"> <summary>Q1 · What closes me?</summary> <p>Opening any other panel that shares my name attribute.</p> </details> <details name="faq"> <summary>Q2 · Open me to test it</summary> <p>Q1 just snapped shut. Radio-button logic, zero scripts.</p> </details> <details name="faq"> <summary>Q3 · Me too</summary> <p>One name group, one open panel.</p> </details>
Self-studyGotchas: summary rules and when NOT to hide content2 min read▶
- summary must be the first child of details. Put it later (or omit it) and the browser renders a default "Details" label - a sure sign of a markup slip.
- The triangle marker is styleable, not sacred. It is the
::markerpseudo-element in CSS; this page's cards replace it with the ▶ you see. HTML stays identical. - Chrome can open them for you: find-in-page (Ctrl/Cmd+F) auto-expands a closed details if the match is inside. Handy, but do not rely on it cross-browser.
- Do not bury critical content. Hiding "how to cancel your subscription" three accordions deep is a dark pattern. Disclosure is for depth-on-demand, not for making things hard to find.
dialog - the conversation box core
A dialog is a box that interrupts the page to talk to the user: confirmations, warnings, forms-in-a-box. The <dialog> element gives you the box, the semantics, and (in modal mode) the dimmed backdrop and focus handling that libraries used to charge kilobytes for.
LiveThe open attribute - a dialog living in the page3 min▶
A <dialog> without the open attribute exists in your markup but renders nothing - it waits. Add open and it appears in the flow of the page as a non-modal box: visible, styled by the browser with a strong border, but not blocking anything around it.
<dialog open> <p><strong>Heads up!</strong> I am a dialog with the open attribute.</p> <p>The page around me still works - that is what non-modal means.</p> </dialog> <p>Regular page content, still clickable.</p>
LiveModal mode - the honest JavaScript half3 min▶
The famous dialog experience - dimmed page, centered box, Esc to close, focus trapped inside - is modal mode, and honesty requires saying it plainly: opening a modal takes one line of JavaScript. The element does all the hard parts; the script is just the doorbell.
<dialog id="confirm">
<p>Really delete everything?</p>
<form method="dialog"><button>Cancel</button></form>
</dialog>
<script>
ask.onclick = () => confirm.showModal();
</script>
What that one showModal() call buys, free: the page behind gets dimmed (styleable via ::backdrop), keyboard focus is trapped inside the box, Esc closes it, and everything behind becomes inert - unclickable and invisible to screen readers. Note the second HTML gem in there: a <form method="dialog"> closes its dialog on submit, no script for the closing side.
showModal() cannot be demoed live here. Paste the pattern above into your own index.html and open it in a real tab - the full modal experience appears.
Self-studyDialog manners2 min read▶
- Modals are interruptions - spend them carefully. Destructive confirmations and must-answer questions earn one; "subscribe to our newsletter" on arrival does not.
- Always provide a visible close button. Esc works in modal mode, but not everyone knows that, and touch users have no Esc.
- Do not fake dialogs with divs. A div overlay gets none of the free behavior: no focus trap, no Esc, no inert background, no announcement. This is the "real button vs onclick div" lesson at box scale.
popover - tooltips and menus with zero scripts core
The newest superpower of the three. Put the popover attribute on any element and it becomes a hidden overlay; point a button at it with popovertarget and the button toggles it. Tooltips, dropdown menus, hint bubbles - the pattern that launched a thousand libraries is now two attributes. Supported in all modern browsers since 2024 (Chrome 114+, Safari 17+, Firefox 125+); older browsers show the button doing nothing, so keep essential content out of popovers for a while yet.
Livepopover + popovertarget - the whole API4 min▶
Two halves: the overlay element carries popover plus an id; the trigger button carries popovertarget pointing at that id. Click toggles it open and closed. Click anywhere else and it dismisses itself ("light dismiss") - the behavior every hand-rolled dropdown gets wrong on the first try.
<button popovertarget="hint"> What is a disclosure widget? </button> <div id="hint" popover> <p>A click-to-reveal control, like the details element from Part 1.</p> </div>
The overlay renders in the browser's top layer - a rendering level above everything on the page. No z-index, no positioning fights: the browser guarantees the popover paints on top.
Self-studypopover vs dialog - picking the right box2 min read▶
| Question | popover | dialog (modal) |
|---|---|---|
| Blocks the rest of the page? | No - page stays live | Yes - background goes inert |
| Click outside to close? | Yes, built in (light dismiss) | No - explicit close or Esc |
| Needs JavaScript to open? | No - popovertarget button | Yes - one showModal() call |
| Best for | Tooltips, menus, hints | Confirmations, blocking forms |
Rule of thumb: if the user must deal with it before continuing, dialog. If it is helpful but skippable, popover. Bonus attribute: popovertargetaction="show" or "hide" makes a button one-directional instead of a toggle - handy for a dedicated ✕ button inside the popover.
Focus and tabindex - interactivity for every hand core
Everything above responds to a mouse. Focus is how it all responds to a keyboard: one element at a time holds the focus, Tab moves it forward, Shift+Tab moves it back, Enter or Space activates. Power users, screen-reader users, and anyone whose mouse just died all live on this system.
LiveTab order follows source order3 min▶
Interactive elements - links, buttons, form fields, summary - are focusable automatically, in the order they appear in your HTML. Write the source in a sensible reading order and keyboard navigation is correct with no extra work. This is why CSS tricks that visually reorder content can quietly break keyboard flow: the eye sees one order, Tab follows another.
<p>Press Tab to walk this form:</p> <input type="text" placeholder="1st stop: name"> <input type="email" placeholder="2nd stop: email"> <p>A link is a stop too: <a href="#">3rd stop</a></p> <button>4th stop: submit</button>
Self-studytabindex: the three values that matter3 min read▶
tabindex="0"- adds a non-interactive element into the natural tab order, at its source position. For the rare custom widget that must be focusable.tabindex="-1"- focusable by script or by link target, but skipped by Tab. This is how skip links land focus on a heading.tabindex="1"or any positive number - a trap, do not use. Positive values hijack the whole page's tab order ahead of everything else, and every future edit has to re-solve the numbering puzzle. Fix the source order instead; that is where tab order belongs.
And the companion rule from CSS-land, stated early because it ruins lives: never remove the focus outline without replacing it. An invisible focus is a keyboard user navigating blind.
...navigation with 40 links...
<main id="main" tabindex="-1">...</main>
First focusable element on the page, usually hidden until focused: one Tab, one Enter, and a keyboard user leaps over your entire navigation. Every serious site has one - check for it with a single Tab press on any government website.
Self-studyBonus vocabulary: the inline elements this page just used2 min read▶
You met them in the wild above - now the formal introductions, from HTML's "other inline text elements" drawer:
<kbd>- a keyboard input, like Tab and Esc throughout this part. Semantics for "the user types this".<mark>- highlighted relevance, like a search-result match. Meaning: "notice this here", not "this is bold".<abbr title="Chief Data and AI Officer">CDAIO</abbr>- an abbreviation whose title attribute holds the expansion; hover one to see the built-in tooltip (popover's tiny ancestor).<small>- fine print: legal lines, side comments, the footnote voice.
Try it yourself - this week ◐ 20-30 min total
- Add an FAQ section to your live project page: an
<h2>plus three<details name="faq">questions people actually ask you. Push it and click through it on the live URL - an interactive feature shipped with zero scripts. - Add one popover: a "What does CDAIO mean?" style hint button next to a jargon word on your page. Test the light dismiss by clicking elsewhere.
- Unplug your mouse (really) and drive your whole page by keyboard: Tab, Enter, Esc. Note every place you got lost - each one is a focus bug you can now name.
- Paste the modal dialog pattern from Part 2 into a scratch file and open it in a real tab. Press Esc, watch the backdrop, try to Tab out of it. Feel how much behavior one line bought.
Official sources covered
This dive teaches the working content of these chapters from web.dev Learn HTML and the MDN Popover API docs. Their interactive checks stay with the originals - our exercises are equivalents, not copies.
Three questions before you go 🎯 ◐ 90 seconds
1 · You want an FAQ where opening one question closes the others. The pure-HTML move is...
Shared name = exclusive group, like radio buttons. There is no accordion element, and onclick means writing the JavaScript this whole page exists to avoid.
2 · A "delete your account?" confirmation that must be answered before anything else - which tool?
Must-answer means modal: inert background, trapped focus, Esc handling. Popovers light-dismiss on any outside click - exactly wrong for a decision you cannot skip.
3 · A teammate sets tabindex="3" to "fix" the tab order. What is the professional response?
Positive values jump ahead of every natural stop on the page and turn future edits into a numbering puzzle. Tab order lives in source order; tabindex 0 joins the natural order, it never reorders it.