Just HTML

Everything on this page — the modal dialogs, the popover menus, the accordion, the pickers, the editor, the drag — is plain HTML doing its job. Open view-source and count the script tags.

0 lines of JavaScript on this entire page

Modal dialogs, no JavaScript invoker commands

For twenty years "open a modal" meant a library. Today a button can command a <dialog> to open — focus is trapped, the page behind is inert, Esc closes it, and the backdrop is a styleable pseudo-element. The browser does all of it.

Hello from <dialog>

Try Tab — focus stays in here. Try Esc — it closes. The rest of the page is inert while I'm open. No focus-trap library was harmed in the making of this dialog.

<button commandfor="greeting" command="show-modal">Open a real modal</button>

<dialog id="greeting">
  ...
  <button commandfor="greeting" command="close">Close</button>
</dialog>

Invoker commands (command/commandfor) are the newest thing on this page — shipping in current Chrome, Edge, and Firefox. In older browsers this exact pattern is a three-line script; the <dialog> element itself has been everywhere since 2022.

Popovers and menus popover API

The popover attribute promotes any element to the top layer: light-dismiss (click outside or press Esc), one-at-a-time management, no z-index wars. popovertarget wires the button declaratively.

This is one. Click anywhere outside to dismiss me — that behavior, plus escape handling and top-layer stacking, is free.
<button popovertarget="tip">What's a popover?</button>
<div id="tip" popover>Light-dismiss, top layer, Esc — all free.</div>

Exclusive accordion with <details name>

Give several <details> elements the same name and the browser enforces "only one open at a time" — the classic accordion widget, as one attribute. Searchable, keyboard-accessible, and it even auto-opens when find-in-page matches hidden text.

Do I need a component library for this?
No. The name attribute makes the group exclusive. Opening one closes the others.
Is it accessible?
It's a native disclosure widget: correct roles, keyboard support, and screen reader announcements come with the element.
Can I style the marker and animate it?
Yes — ::marker, ::details-content, and CSS transitions. That's the CSS wing's department.
<details name="faq" open> <summary>...</summary> ... </details>
<details name="faq">      <summary>...</summary> ... </details>
<details name="faq">      <summary>...</summary> ... </details>

Form controls people rebuild for no reason

Every control below is one element. Each ships with a mobile-optimized UI, keyboard support, and assistive-technology wiring that a div-based rebuild has to earn back line by line.

Form validation before a single line of script

Try submitting empty, then fix the fields and watch the borders change. required, type="email", minlength, and pattern block the submission and explain why in the user's own language. The green/red styling is the CSS :user-valid / :user-invalid pseudo-classes — which only kick in after you interact, so the form doesn't scold you on arrival.

Remember Module 06: this is UX, not security — the server still re-checks everything.

A text editor in one attribute

contenteditable turns any element into an editor — caret, selection, undo history, spellcheck, IME support, the lot. Every "rich text editor" you've used sits on top of this.

Click anywhere in this card and start typing

This is a real editing surface. Select text. Hit Cmd/Ctrl+Z. Misspell somethng and watch the squiggle appear. Paste rich text from another app.

Native drag — the start of the story

Add draggable="true" and the browser gives you the pickup: the drag ghost, the cursor, the OS-level drag session. Try dragging these cards around — even into another app's window. Honesty box: making something catch the drop is JavaScript's half of the deal. HTML serves; JS returns.

  • ⠿ Drag me — watch the ghost image appear
  • ⠿ Drag me into a text field somewhere
  • ⠿ Images and links are draggable by default

A media player in one tag

Play/pause, scrubbing, volume, fullscreen, AirPlay/cast buttons, keyboard control, picture-in-picture — controls brings the whole player. The audio below isn't even a file on disk: it's a WAV baked into the page as a data: URI (Module 05 says hello).

Audio — a chime embedded directly in this HTML file:

Video — with a poster frame and captions, streamed from MDN's CC0 samples (needs the network):

<audio controls src="data:audio/wav;base64,UklGRu…"></audio>
<video controls src="flower.mp4"></video>

Lightning round

One-liners that surprise people, live in the second column:

MarkupLive
<a href="…" download> Download a file (generated from a data: URI)
<a href="mailto:…?subject=…"> Email with a pre-filled subject
<ruby> 漢kan字ji — pronunciation guides, natively typeset
dir="auto" مرحبا — this span detected its own text direction
<input type="search">
<img loading="lazy"> Below-the-fold images that don't download until needed — an attribute, not an intersection-observer library
<abbr title> / <kbd> Hover WYSIWYG, press Ctrl+K