Display content inline whenever possible.
Put content on its own route / page.
Don’t open a modal from another modal.
<dialog
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
id="this-modal-id"
>
<h2 id="modal-title">The Modal Title</h2>
<!-- Modal Contents -->
</dialog>
aria-labelledby="title-id"
aria-label="Modal Title"
Open Button (outside of modal)
<button aria-controls="modal-id">
Open {Modal Name}
</button>
Close Button (inside modal)
<button>Close {Modal Name}</button>
Close Button (remixed)
<button>
<span class="sr-only">
Close {Modal Name}
</span>
<svg aria-hidden="true"></svg>
</button>
Scrim (optional), outside of Modal
<button aria-hidden="true">
<span class="sr-only">
Close {Modal Name}
</span>
</button>
Open | Closed |
---|---|
open |
inert |
aria-hidden="true" |
Future Feature: inert
polyfill
function openModal () {
modal.removeAttribute('aria-hidden')
modal.removeAttribute('inert')
modal.setAttribute('open', true)
}
function closeModal () {
modal.setAttribute('aria-hidden', 'true')
modal.setAttribute('inert', true)
modal.removeAttribute('open')
}
<button>
scrim)keyup
eventtabindex="0"
)[aria-controls="id"]
)Connect CSS to aria-hidden
attribute:
.modal[aria-hidden="true"] {
visibility: hidden;
/* Other CSS */
}
visibility: hidden | visible
not
display: none | block
For smooth animations:
opacity
transform
Respect motion preferences.
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0 !important;
animation-duration: 0 !important;
}
}
overflow-y: auto
body
while the modal is open🙅
These are “clever,” but don’t communicate state to screen readers.
Put modal markup on its own page.
Put them in a dialog
when JS works.
jdsteinbach