The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Create a disclosure | <details>
<summary>More options</summary>
<p>Details</p>
</details> | View examples |
| Open initially | <details open>
<summary>Status</summary>
<p>Ready</p>
</details> | View examples |
| Group disclosures | <details name="faq">
<summary>Question</summary>
<p>Answer</p>
</details> | View examples |
| Declare a dialog | <dialog id="settings"><p>Settings</p></dialog> | View examples |
| Open modally | document.querySelector('#settings').showModal() | View examples |
| Open non-modally | document.querySelector('#settings').show() | View examples |
| Close with a result | document.querySelector('#settings').close('saved') | View examples |
| Submit and close | <form method="dialog">
<button value="cancel">Cancel</button>
</form> | View examples |
| Style the modal backdrop | dialog::backdrop { background: rgb(0 0 0 / 55%); } | View examples |
| Declare an auto popover | <div id="help" popover>Helpful text</div> | View examples |
| Toggle declaratively | <button popovertarget="help">Help</button> | View examples |
| Choose an action | <button popovertarget="help" popovertargetaction="show">
Show help
</button> | View examples |
| Keep a popover open | <div id="status" popover="manual">Saved</div> | View examples |
| Show with JavaScript | document.querySelector('#status').showPopover() | View examples |
| Style an open popover | [popover]:popover-open { opacity: 1; } | View examples |
Use the platform's interactive elements before recreating them with generic containers. Details provides a disclosure, dialog provides modal or non-modal windows, and popover provides lightweight top-layer UI. Give every control a clear name, preserve keyboard behavior, and use JavaScript only for state the declarative APIs cannot express.
Step by step
Detailed examples
Reveal optional content with details
The first summary child supplies the disclosure label and activation control. Content after it is revealed when open is present. A shared name creates an exclusive group, but each details element still needs the same name and should appear in a sensible document order.
<details name="faq" open>
<summary>Can I export my data?</summary>
<p>Yes. Open Settings, then choose Export.</p>
</details>
<details name="faq">
<summary>Can I delete my account?</summary>
<p>Yes. The confirmation explains what will be removed.</p>
</details> Note: Do not place another interactive control inside summary; the summary itself is the disclosure control.
Choose modal or non-modal dialog behavior
A dialog has no implicit opening trigger. Call show() for a window that can coexist with the page, or showModal() when users must respond before continuing. Do not simulate opening by setting open directly for a modal: that skips top-layer and inert behavior.
<button id="open-inspector">Open inspector</button>
<dialog id="inspector">
<p>Page diagnostics</p>
<button id="close-inspector">Close</button>
</dialog>
<script>
const dialog = document.querySelector('#inspector');
document.querySelector('#open-inspector').addEventListener('click', () => dialog.show());
document.querySelector('#close-inspector').addEventListener('click', () => dialog.close());
</script> Complete modal interactions
showModal() gives modal dialogs top-layer placement and makes content outside them inert. Include an obvious close path. A form with method=dialog closes through submit buttons and records the activated button's value; inspect returnValue in the close event. Escape normally fires cancel and closes the dialog unless that event is deliberately prevented.
<button id="remove">Remove item</button>
<dialog id="confirm-remove" aria-labelledby="confirm-title">
<form method="dialog">
<h2 id="confirm-title">Remove this item?</h2>
<p>This action cannot be undone.</p>
<button value="cancel">Cancel</button>
<button value="remove">Remove</button>
</form>
</dialog>
<script>
const dialog = document.querySelector('#confirm-remove');
document.querySelector('#remove').addEventListener('click', () => dialog.showModal());
dialog.addEventListener('close', () => console.log(dialog.returnValue));
</script> Use popovers for lightweight top-layer UI
The popover attribute hides an element until a control or method opens it. The default auto state supports light-dismiss with Escape or an outside interaction and normally closes other auto popovers. popovertarget creates the relationship and exposes expanded state to accessibility APIs.
<button type="button" popovertarget="keyboard-help">Keyboard help</button>
<div id="keyboard-help" popover>
<p><kbd>Ctrl</kbd> + <kbd>K</kbd> opens search.</p>
</div> Control popover lifetime explicitly
Use popovertargetaction when a control should only show or hide rather than toggle. Manual popovers do not light-dismiss, so the application must provide a reliable close path. Programmatic methods are useful for events without a natural invoking button, such as status messages.
<button id="show-status">Show status</button>
<div id="status" popover="manual">
<p>Upload complete.</p>
<button popovertarget="status" popovertargetaction="hide">Dismiss</button>
</div>
<script>
const status = document.querySelector('#status');
document.querySelector('#show-status').addEventListener('click', () => status.showPopover());
</script> Style top-layer states without hiding semantics
Modal dialogs and displayed popovers participate in the top layer, outside ordinary stacking-context competition. Use ::backdrop for the layer behind a modal and :popover-open for displayed popovers. Preserve visible focus and sufficient contrast; animation must not make controls unavailable while state changes.
dialog {
border: 0;
border-radius: 0.75rem;
max-inline-size: min(32rem, 90vw);
}
dialog::backdrop {
background: rgb(15 23 42 / 60%);
}
[popover] {
border: 1px solid #94a3b8;
border-radius: 0.5rem;
}
[popover]:popover-open {
opacity: 1;
} Local code tester
Try a disclosure, dialog, and popover
Open each native interaction and inspect its keyboard, dismissal, and top-layer behavior.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



