Last active
June 13, 2022 14:11
-
-
Save nolanlawson/13cbc222f8aa47ffd3e5e28838122d4b to your computer and use it in GitHub Desktop.
Modal with inert demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Pseudo-dialog using inert and shadow DOM</title> | |
<style> | |
body { | |
margin: 0 auto; | |
max-width: 400px; | |
padding: 40px; | |
} | |
[role=dialog] { | |
display: none; | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
z-index: 2; | |
background-color: rgba(30, 30, 30, 0.3); | |
} | |
[role=dialog].open { | |
display: flex; | |
} | |
.dialog-inner { | |
max-width: 90vw; | |
margin: 0 auto; | |
overflow-x: auto; | |
padding: 20px; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Pseudo-dialog using inert and shadow DOM</h1> | |
<p>Browser supports <code>inert</code>? <span id="supports"></span></p> | |
<p>Tab around with the keyboard, open a pseudo-dialog using <code>inert</code>, press Esc to close.</p> | |
<button>Focusable button</button> | |
<button class="modal-button">Click to open modal dialog</button> | |
<button>Another focusable button</button> | |
<div role="dialog"> | |
<div class="dialog-inner"> | |
<div> | |
<button>Light button</button> | |
<open-shadow></open-shadow> | |
<button>Another light button</button> | |
</div> | |
<video controls src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"></video> | |
<div> | |
<button>Light button</button> | |
<closed-shadow></closed-shadow> | |
<button>Another light button</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.querySelector('#supports').textContent = 'inert' in HTMLElement.prototype ? 'Yes' : 'No' | |
function addStyle(root) { | |
const css = ` | |
button:focus { | |
outline: 4px dashed blue; | |
outline-offset: -2px; | |
} | |
button { | |
font-size: 1.2em; | |
padding: 5px; | |
margin: 5px; | |
}` | |
const style = document.createElement('style') | |
style.textContent = css | |
root.appendChild(style) | |
} | |
class ClosedShadow extends HTMLElement { | |
constructor () { | |
super() | |
const shadow = this.attachShadow({ mode: 'closed' }) | |
shadow.innerHTML = '<button>Closed shadow button!</button>' | |
addStyle(shadow) | |
} | |
} | |
class OpenShadow extends HTMLElement { | |
constructor () { | |
super() | |
const shadow = this.attachShadow({ mode: 'open' }) | |
shadow.innerHTML = '<button>Open shadow button!</button>' | |
addStyle(shadow) | |
} | |
} | |
customElements.define('closed-shadow', ClosedShadow) | |
customElements.define('open-shadow', OpenShadow) | |
function openOrCloseDialog(open) { | |
for (const element of document.body.children) { | |
if (element !== dialog) { | |
if (open) { | |
element.setAttribute('inert', 'true') | |
} else { | |
element.removeAttribute('inert') | |
} | |
} | |
} | |
dialog.classList.toggle('open', open) | |
} | |
const dialog = document.querySelector('[role=dialog]') | |
const launchButton = document.querySelector('.modal-button') | |
launchButton.addEventListener('click', () => { | |
openOrCloseDialog(true) | |
dialog.querySelector('button').focus() | |
}) | |
dialog.addEventListener('keydown', e => { | |
if (e.key === 'Escape') { | |
e.preventDefault() | |
e.stopPropagation() | |
openOrCloseDialog(false) | |
launchButton.focus() | |
} | |
}) | |
addStyle(document.head) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment