<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>The new HTML 5.2 dialog element</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>HTML 5.2 <code>dialog</code> element examples</h1>
<p>Works natively in Chrome and Opera at present [08/01/2018].<br>JavaScript ES6 applied to support non-supporting browsers. <a class=lnk href="https://caniuse.com/#feat=dialog" target=_blank title="[new window]">Can I use: dialog</a></p>
<p class=dialogSupported>This browser supports <code>dialog</code></p>
<p class=noDialogSupport>This browser doesn't natively support <code>dialog</code></p>
<h2>Full screen modal: <code>dialog.showModal()</code></h2>
<dialog id=dialog_1>
<!-- <div class=content> -->
<h2>Dialog one title</h2>
<p>Dialog copy content with a <a class=lnk href>contained link</a> to test keyboard focus.</p>
<p><kbd>TAB</kbd> key focus is locked into the modal.<br><kbd>ESC</kbd> or click button to exit.</p>
<button>Exit dialog</button>
<!-- </div> -->
</dialog>
<button id=btn-dialog_1>Button one <small>(follows dialog one)</small></button>
<button id=btn-dialog_2>Button two <small>(precedes dialog two)</small></button>
<dialog id=dialog_2>
<h2>Dialog 2 title</h2>
<p>Dialog copy content with a <a class=lnk href>contained link</a> to test keyboard focus.</p>
<p><kbd>TAB</kbd> key focus is locked into the modal.<br><kbd>ESC</kbd> or click button to exit.</p>
<button>Exit dialog</button>
</dialog>
<h2>Local modal: <code>dialog.show()</code></h2>
<p>Purposefully swapped <code>button</code> positions. Both precede <code>dialog</code> HTML.</p>
<!-- Swapped button positions -->
<button id=btn-dialog_4 data-dialog-type=show>Dialog four</button>
<button id=btn-dialog_3 data-dialog-type=show>Dialog three</button>
<dialog id=dialog_3>
<h2>Dialog 3 title</h2>
<p>Dialog copy content with a <a class=lnk href>contained link</a> to test keyboard focus.</p>
<button>Exit dialog</button>
</dialog>
<dialog id=dialog_4>
<h2>Dialog 4 title</h2>
<p>Dialog copy content with a <a class=lnk href>contained link</a> to test keyboard focus.</p>
<button>Exit dialog</button>
</dialog>
<p>Note how <code>z-index</code> layering remains in source code order.</p>
<p>Note when multiple <code>dialog</code>s are open reclicking the <code>button</code> doesn't bring the <code>dialog</code> to the front.</p>
<!-- <p><a class=lnk href>Empty link</a> to test if exiting modal returns user to activating button.</p> -->
<h2>Added via JS</h2>
<ul>
<li>Return focus to the activating button upon close.</li>
<li>Keyboard trap implemented for <code>showModal()</code> but not <code>show()</code>.</li>
</ul>
<h2>Working on</h2>
<ul>
<li>Currently investigating what should occur, keyboard chain wise, when opened via <code>show()</code>.</li>
<li>Requires full testing with Voiceover and JAWS. None done so far.</li>
</ul>
<p class=myStuff><style>.myStuff{z-index:10;font-weight:100;color:#777;font-size:16px;position:fixed;left:0;width:100vw;max-width:none;bottom:0;margin:0;background-color:hsl(269,19%,30%);text-align:center;padding:.125em}.myStuff_lnk,.myStuff_lnk:visited{color:#ddd;text-decoration:none;border-bottom:1px solid rgba(255,255,255,.4);transition:all .3s ease-out}.myStuff_lnk:focus,.myStuff_lnk:hover{color:#fff;border-bottom-color:rgba(255,255,255,1)}</style><strong style="color:#fff;padding-right:.5rem">Hire me: </strong> <a class=myStuff_lnk target=_blank title="[LinkedIn - new window]" href="https://www.linkedin.com/in/mikefoskett">Mike Foskett</a> — <a class=myStuff_lnk target=_blank title="[new window]" href="https://codepen.io/2kool2/pens/popular/?grid_type=list#">Popular pens</a> — <a class=myStuff_lnk target=_blank title="[new window]" href="https://codepen.io/2kool2/pens/public/?grid_type=list#">Latest pens</a> — <a class=myStuff_lnk target=_blank title="[new window]" href="https://websemantics.uk/">webSemantics</a></p>
<script src="js/index.js"></script>
</body>
</html>
/*Downloaded from https://www.codeseek.co/2kool2/the-new-html-52-dialog-element-xppLgd */
@media (min-width: 40em) {
:root {
/* Rough responsive fonts */
font-size: calc(1vw + 1vh + .5vmin);
}
}
body {
font-family: sans-serif;
line-height: 1.5;
text-align: center;
padding-bottom: 2rem;
}
body {
color: hsl(269,19%,30%);
background-color: hsla(32,100%,85%,.35);
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.4'/%3E%3C/filter%3E%3C/defs%3E%3C!-- %3Cpath filter='url(%23a)' opacity='.3' d='M0 0h1200v256H0z'/%3E--%3E%3Crect filter='url(%23a)' opacity='.3' width='100%25' height='100%25'/%3E%3C/svg%3E");
}
h1,h2 {
font-weight: 100;
margin-top: 2rem;
margin-bottom: 1rem;
}
p {
max-width: 40em;
margin: 1rem auto;
}
.lnk {
color: hsl(211, 100%, 40%); /* Brightest WCAG against #DAE5F2 */
text-decoration-skip: ink;
text-decoration-color: hsla(211, 100%, 40%, .25);
outline: 0 solid #fff;
transition: background-color .3s;
}
.lnk:hover,
.lnk:focus {
color: hsl(211, 100%, 46%); /* Brightest WCAG against #fff */
background-color: #fff;
text-decoration-color: hsla(211, 100%, 46%, 1);
outline: .25rem solid #fff;
transition: outline .3s;
}
kbd,
code {
font-size: inherit;
font-weight: 100;
font-family: monospace, monospace;
text-shadow: .03125em .03125em #fff;
background-color: hsla(32,100%,100%,.35);
/* outline: .25em solid hsla(32,100%,100%,.35); */
padding: 0 .25em;
}
ul {
max-width: 30em;
text-align: left;
margin: 1rem auto;
}
button {
margin: 1rem;
font-size: 1.25rem;
padding: 1rem 1.5rem;
color: inherit;
background-color: hsla(32,100%,100%,.75);
border: 1px solid #fff;
box-shadow: 0 2px 4px rgba(0,0,0,.5);
transition: all .3s ease-out;
cursor: pointer;
}
button:hover {
color: #000;
background-color: hsla(32,100%,100%,1);
box-shadow: 0 4px 8px rgba(0,0,0,.25);
}
dialog,
dialog[close],
dialog[aria-hidden="true"] {
/* display: none; */
visibility: hidden;
opacity: 0;
transition:
display 0s linear 2s,
visibility 0s linear 2s,
opacity 1s ease-out 0s;
}
dialog[open],
dialog[aria-hidden="false"]{
display: block;
visibility: visible;
opacity: 1;
color: inherit;
background-color: hsla(32,50%,95%,1);
transition:
display 0s linear 0s,
visibility 0s linear 0s,
opacity 1s ease-out 0s;
}
dialog::backdrop{
background-color: hsla(32,50%,10%,.7);
}
/* Making a dialog work in unsupported browsers */
dialog {
--spacing: 1rem;
box-sizing: border-box;
border: 2px solid #000;
padding: var(--spacing);
}
dialog[aria-hidden][data-dialog-type="showModal"] {
position: fixed;
z-index: 20;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
dialog[aria-hidden][data-dialog-type="show"] {
position: absolute;
left: 50%;
transform: translate3d(-50%, 0, 0);
}
.-js-dialogBg {
position: fixed;
z-index: 10;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: hsla(32,50%,10%,.7);
}
.-js-dialogBg:hover {
/* Stolen from trickle.js. SVGs will not work here */
cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAANpJREFUOBGNkz0KAjEQhYPYWXgCKws7LcXWyt7WG4i9jegBvIJ4AvEyXsRCsBDiN0sGkiE/O/A2O9n3viS7rPPeb9ETrVzPwrtHDzR1XF5I6oPWLQaeq5hDXQRw0I6xCuF5HH7Tz7oFuTkhrSyEhza8THaLoQhphpWUg/QOFyA/AFpy5nTbGrIjxvg4AiiGBzYc+rGZH9KPzFy+ZbX4bX9l+VDZr5NQMMbhbtvMxccpQ3JhpTchtXATQviItIpvW0CY7HHm8c9UDRd2chbABt3RQk2tEe8O3dDkD4JQ4iOR7BMpAAAAAElFTkSuQmCC"), pointer;
}
.dialogSupported,
.noDialogSupport {
font-weight: bold;
}
.dialogSupported,
.supportsDialog .noDialogSupport {
display: none;
}
.supportsDialog .dialogSupported {
display: inline;
}
/*Downloaded from https://www.codeseek.co/2kool2/the-new-html-52-dialog-element-xppLgd */
// Not required but useful
if (typeof HTMLDialogElement === "function") {
document.documentElement.classList.add("supportsDialog");
}
(function() {
"use strict";
const bgClass = "-js-dialogBg";
const dataAttr = "data-dialog-type";
const _removeDialogBackground = () => {
const bg = document.querySelector("." + bgClass);
if (bg) {
document.body.removeChild(bg);
}
};
const _dialogClose = (dialog) => {
if (dialog.close) {
dialog.close();
} else {
dialog.setAttribute("aria-hidden", "true");
_removeDialogBackground();
}
dialog.btnOpen.focus();
};
const _appendDialogBackground = (dialog) => {
const bg = document.createElement("div");
const hasBg = document.querySelector("." + bgClass);
if (!hasBg) {
bg.addEventListener("click", function() {
_dialogClose(dialog);
});
bg.classList.add(bgClass);
document.body.appendChild(bg);
}
};
const _keydown_modal = (e) => {
const target = e.target;
const parentDialog = target.closest("dialog");
if (!parentDialog) {
return false;
}
// console.log(target.tagName, parentDialog.tagName);
// ESC key on anything actionable
if (e.which === 27) {
_dialogClose(parentDialog);
}
// tab key and shift on the first element
if (e.which === 9 && e.shiftKey && target === parentDialog.firstElementChild) {
e.preventDefault();
parentDialog.lastElementChild.focus();
}
// tab key and not shift on the last element.
if (e.which === 9 && !e.shiftKey && target === parentDialog.lastElementChild) {
e.preventDefault();
parentDialog.firstElementChild.focus();
}
};
const _showModal = (dialog) => {
if (dialog.showModal) {
dialog.showModal();
} else {
_appendDialogBackground(dialog);
dialog.setAttribute("aria-hidden", "false");
dialog.setAttribute(dataAttr, "showModal");
}
dialog.addEventListener("keydown", _keydown_modal, false);
};
const _show = (dialog) => {
if (dialog.show) {
dialog.show();
} else {
dialog.setAttribute("aria-hidden", "false");
dialog.setAttribute(dataAttr, "show");
}
};
const _dialogOpen = (dialog) => {
const isShowModal = dialog.btnOpen.getAttribute(dataAttr) !== "show";
if (isShowModal) {
_showModal(dialog);
} else {
_show(dialog);
}
dialog.firstElementChild.focus();
};
const dialogs = document.querySelectorAll("dialog");
for (const dialog of dialogs) {
// Close button
const btnClose = dialog.querySelector("button");
if (btnClose) {
btnClose.addEventListener("click", () => _dialogClose(dialog));
}
// Close when clicking on dialog::backdrop
// Method and code from: https://codepen.io/keithjgrant/pen/eyMMVL
// - Only works when a container inside completely fills the dialog.
// - first-child focus would require adjustment to suit.
// dialog.addEventListener('click', (event) => {
// console.log(event.target);
// if (event.target === dialog) {
// _dialogClose(dialog);
// }
// }, false);
// Open Button
const btnOpen = document.getElementById("btn-" + dialog.id);
if (btnOpen) {
btnOpen.addEventListener("click", () => {
dialog.btnOpen = btnOpen;
_dialogOpen(dialog);
});
}
// focussable first child
const firstElement = dialog.firstElementChild;
if (firstElement) {
firstElement.setAttribute("tabindex", "0");
}
}
})();