Skip to content

Instantly share code, notes, and snippets.

Created September 16, 2014 12:34
Show Gist options
  • Save anonymous/8f69eee216e053658f8e to your computer and use it in GitHub Desktop.
Save anonymous/8f69eee216e053658f8e to your computer and use it in GitHub Desktop.
A Pen by Scott.

Accessible Modal Window

an accessible modal window with aria support written with vanilla javascript

A Pen by Scott on CodePen.

License.

<div id="page">
<div class="menu">
<button class="btn" type="button" id="modal_open">Open the Modal</button>
</div>
<article class="content-area">
<h1>
Demo:<br />
An accessible Modal Window with JavaScript &amp; CSS
</h1>
<p>
This modal window is made with plain old semantic mark-up, CSS and
a very little bit of JavaScript.
</p>
<p>
Check out the source code to see how it works!
</p>
<form action="#">
<label for="test" class="label">Label for Input</label>
<input type="text" id="test" class="input" />
<label for="test2" class="label">Label for Second Input</label>
<input type="text" id="test2" class="input" />
<label for="test3" class="label">Label for Third Input</label>
<input type="text" id="test3" class="input" />
</form>
<p>
Here's a link to the <a href="https://en.wikipedia.org/wiki/Modal_window">wikipedia entry on modal windows</a>.
</article> <!-- end .content-area -->
</div> <!-- end #page -->
<div class="modal-overlay" id="modal-dialog"
aria-hidden="true" role="dialog"
aria-labelledby="modal-title">
<div class="modal-content" id="modal-holder" role="document">
<h1 id="modal-title">Modal Title</h1>
<form>
<label for="name">Name:</label>
<input type="text" id="name" class="input" placeholder="Gimmie ur Name" />
<label for="email">Email:</label>
<input type="email" id="email" class="input" placeholder="Gimmie ur Email" />
<input type="submit" class='btn' value="Submit Form" />
</form>
<button class="btn-close" id="modal_close" type="button" aria-label="close">
&times;
</button>
</div> <!-- end .modal-content -->
</div> <!-- end .modal-overlay -->
(function() {
'use strict';
// list out the vars
var mOverlay = getId('modal-dialog'),
mOpen = getId('modal_open'),
mClose = getId('modal_close'),
modal = getId('modal-holder'),
modalOpen = false,
lastFocus;
// Let's cut down on what we need to type to get an ID
function getId ( id ) {
return document.getElementById(id);
}
// Let's open the modal
function modalShow () {
lastFocus = document.activeElement;
mOverlay.setAttribute('aria-hidden', 'false');
modalOpen = true;
modal.setAttribute('tabindex', '0');
modal.focus();
}
// binds to both the button click and the escape key to close the modal window
// but only if modalOpen is set to true
function modalClose ( event ) {
if (modalOpen && ( !event.keyCode || event.keyCode === 27 ) ) {
mOverlay.setAttribute('aria-hidden', 'true');
modal.setAttribute('tabindex', '-1');
modalOpen = false;
lastFocus.focus();
}
}
// Restrict focus to the modal window when it's open.
// Tabbing will just loop through the whole modal.
// Shift + Tab will allow backup to the top of the modal,
// and then stop.
function focusRestrict ( event ) {
document.addEventListener('focus', function( event ) {
if ( modalOpen && !modal.contains( event.target ) ) {
event.stopPropagation();
modal.focus();
}
}, true);
}
// Close modal window by clicking on the overlay
mOverlay.addEventListener('click', function( e ) {
if (e.target == modal.parentNode) {
modalClose( e );
}
}, false);
// open modal by btn click/hit
mOpen.addEventListener('click', modalShow);
// close modal by btn click/hit
mClose.addEventListener('click', modalClose);
// close modal by keydown, but only if modal is open
document.addEventListener('keydown', modalClose);
// restrict tab focus on elements only inside modal window
window.addEventListener('keypress', focusRestrict);
})();
/*
Modal Overlay
*/
.modal-overlay {
background:rgba(0,0,0,.8);
height: 100%;
left: 0;
display: flex;
overflow: auto;
padding: 1.5em;
position: fixed;
top: 0;
transition: opacity .2s;
width: 100%;
z-index: -1;
}
.modal-overlay[aria-hidden="true"] {
opacity: 0;
visibility: hidden;
}
.modal-overlay[aria-hidden="false"] {
opacity: 1;
visibility: visible;
z-index: 2;
}
/*
Modal Content Area
*/
.modal-content {
background: #efefef;
margin: auto;
max-width: 800px;
overflow: auto;
overflow-x: hidden;
padding: 1.5em;
position: relative;
transform: scale(.8);
transition: transform .3s;
width: 100%;
}
.modal-overlay[aria-hidden="false"] .modal-content {
transform: scale(1);
}
/*
General Modal Content
*/
#modal-title {
margin-top: 0;
padding-right: 1.25em;
}
/*
Close Modal Button
*/
.btn-close {
background: none;
border: none;
cursor: pointer;
font-family: arial;
font-size: 2em;
font-weight: 800;
line-height: 1;
padding: 0;
position: absolute;
right: .25em;
top: .25em;
z-index: 2;
}
.btn-close:hover {
color: #c12f48;
}
.btn-close:focus {
outline: 1px dotted;
}
/*
This is here purely for demo styling
*/
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
font-family: arial;
}
body, html {
background: #fdf7f8;
color: #450c13;
font-size: 20px;
line-height: 1.3;
margin: 0;
padding: 0;
-moz-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
}
a {
color: #921c2b;
}
a:hover {
color: #c12f48;
}
.content-area {
margin: auto;
max-width: 900px;
padding: 20px;
}
.menu {
background: #fff;
border-bottom: 1px solid #bbb;
margin: 0;
padding: 12px 8px 0;
text-align: center;
}
input[type="submit"],
input[type="button"] {
-webkit-appearance:none;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
.btn:focus,
.input:focus,
.modal-content:focus {
outline: 1px solid #ccc;
box-shadow: 0 0 4px #e8a1ad;
}
.btn {
background: #921c2b;
border: 1px solid #4d0912;
color: #fff;
cursor: pointer;
font-size: 1em;
line-height: 1;
margin-bottom: 12px;
padding: 16px 24px;
position: relative;
text-align: center;
transition: transform .2s, background .2s;
}
.btn:hover, .btn:focus {
background: #c12f48;
transform: scale(1.1);
z-index: 3;
}
label {
display: inline-block;
font-size: 1.5em;
font-weight: bold;
margin-bottom: .5em;
}
.input {
border: 1px solid #333;
display: block;
font-size: 1.4em;
margin-bottom: 1em;
min-width: 230px;
padding: 8px;
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment