WordPress Component Library
10up Engineering

Modal

The modal dialog component is a standard and accessible JavaScript plugin that was converted from a jQuery plugin by Scott Ohara, you can view the plugin on Github. This component is keyboard accessible, reusable, and properly traps focus while the dialog is open. It also exposes a small API via a callback function you can hook into if you need to extend the functionality. No jQuery is required.

HTML

<script>
	/* Add to <head> */
	// Remove no-js and add 'js' to the HTML
	document.documentElement.className = document.documentElement.className.replace('no-js', ' ');
	document.documentElement.className += ' js ';
</script>

This component requires a js class to be present on the html element to fully function. If you’re using a script like Modernizr, it will handle this for you. If not, you’ll need to add the above script to the head of the document. Adding it into the head will assure there will be no jumpiness in the UI while the JavaScript and CSS are loading.

<div class="content-area">

	<p>
		Example paragraph goes here.
		<a data-action="modal-open"
			 data-modal-open="primary_modal"
			 data-set-modal-title="Test Title"
			 href="#primary_modal">
			 Open Modal with a Link
		</a>
	</p>

	<div id="primary_modal" class="a11y-modal no-js-hide-modal">

		<div class="modal">

			<div class="modal__intro">
				<h3 id="small_modal_title" data-modal-title class="modal__intro__title">Small Modal Window</h3>
				<p>intro text <a href="#!">test</a></p>
			</div>

			<div class="modal__content">
				<p>Content goes here that talks about a thing that you couldn't doing the normal DOM flow for some reason. <a href="#!">test</a></p>
			</div><!--/.modal__content-->

			<!-- Outro content here -->
			<div class="modal__outro">
				<p>Outro message</p>
				<a data-modal-close
					 class="modal__outro__close"
					 href="#x">
					<span aria-hidden="true"></span>
				</a>
			</div>

		</div> <!-- end .modal -->
	</div>

</div>


<button type="button" data-modal-alert="true" data-action="modal-open" aria-controls="normal_modal_b" data-set-modal-title="Test Title" data-href="#normal_modal_b">
 Open Modal with a Button
</button>

<div id="normal_modal_b"
		 class="a11y-modal no-js-hide-modal"
		 data-modal-alert="true"
		 data-modal-stay="true">

	<div class="modal">

		<div class="modal__intro">
			<h3 id="normal_modal_b"
					data-modal-title
					class="modal__intro__title">
				Normal Modal Window
			</h3>
			<p>
				intro text
			</p>
		</div>


		<!-- main modal content here -->
		<div class="modal__content">
			<p>
				Content goes here that talks about a thing that you couldn't do
				in the normal DOM flow for some reason.
			</p>
		</div>


		<!-- Outro content here -->
		<div class="modal__outro">
			<p>Outro message?</p>
			<a data-modal-close
				 class="modal__outro__close"
				 href="#x">
				<span aria-hidden="true"></span>
			</a>
		</div>

	</div> <!-- end .modal -->
</div><!--/.a11y-modal-->

SCSS Plugin | Mixins

// Breakpoints
$bp-small:          40.625em !default;      // 650px
$bp-medium:         53.125em !default;      // 850px
$bp-large:          62.5em !default;        // 1000px

// Imports
@import 'flexbox-mixins';

// Namespace, if you want it (update the HTML too though)
$ns: '' !default;

// Variables
$modal-overlay--bg:                 rgba(0, 0, 0, .666) !default;
$modal-overlay--padding:            1.5625em !default; // 25px

$modal--bg:                         #fff !default;

$modal--max-width:                  50em !default; // 800px
$modal--min-width:                  16.875em !default; // 270px
$modal--padding:                    2em !default; // 32px

$modal--z-index:                    99 !default;

$modal__close--size:                2em !default;
$modal__close--padding:             4px !default;
$modal__close--offset:              28px !default;

// Component Sass

// to prevent the document from scrolling in the background,
// we need these rules in place when a modal is open
.modal-is-open,
.modal-is-open body {
	height: 100%;
	overflow: hidden;
	position: absolute;
	width: 100%;
}

//
.js .#{$ns}modal-overlay,
.js .#{$ns}a11y-modal {
	@include flexbox();
	box-sizing: border-box;
	background: $modal-overlay--bg;
	height: 100%;
	left: 0;
	opacity: 0;
	overflow: auto;
	padding: $modal-overlay--padding;
	position: fixed;
	top: 0;
	transition: opacity .2s ease-in-out;
	visibility: hidden;
	width: 100%;
	z-index: -1;

	&[aria-hidden="false"] {
		opacity: 1;
		visibility: visible;
		z-index: $modal--z-index;

		.#{$ns}modal {
			transform: scale(1) translateY(0px);
		}
	}
}

// the actual modal content block
.#{$ns}modal {
	box-sizing: border-box;
	background: $modal--bg;
	margin: auto;
	max-height: 90%;
	max-width: $modal--max-width;
	min-width: $modal--min-width;
	overflow: auto;
	overflow-x: hidden;
	padding: $modal--padding;
	position: relative;
	transform: scale(0.8) translateY(-30px);
	transition: transform .3s ease-in-out;
	width: 100%;

	&--full-width {
		max-width: 100%;
	}

	&--content-scroll {
		overflow: hidden;

		.#{$ns}modal__content {
			height: 300px;
			overflow: auto;
			transition: height .2s ease-in-out;

			@media screen and ( min-height: $bp-small ) {
				height: 400px;
			}

			@media screen and ( min-height: $bp-medium ) {
				height: 600px;
			}

			@media screen and ( min-height: $bp-large ) {
				height: 700px;
			}
		}
	}

}

.#{$ns}modal__outro {

	&__close {
		cursor: pointer;
		font-size: $modal__close--size;
		line-height: 1;
		padding: $modal__close--padding;
		position: absolute;
		right: $modal__close--offset;
		text-decoration: none;
		top: $modal__close--offset;
	}
}

// CSS for when there is no JavaScript
.no-js .no-js-hide-modal,
.no-js button[data-action='modal-open'] {
	display: none;
}

.no-js .no-js-hide-modal:target {
	display: block;
}

JS Usage | Plugin | Extension

TenUp.modal({
	'target': '#primary_modal',
	'trigger': '#modal_opener'
}, function() {

	/*
	This is your callback function, if you want it.
	If fires after the modals are set up

	You could load a template in here or maybe open it on load
	by programatically clicking the open button
	*/

});

TenUp.modal({
	'target': '#normal_modal_b',
	'trigger': '#modal_b_opener'
});

TenUp.modal({
	'target': '#normal_modal_1',
	'trigger': '#modal_1_opener'
});

JavaScript API

TenUp.modal( { options }, callback );

This is the main method to call the plugin. It currently takes two arguments, an options object and callback function.

options

Currently recognizes the following: target, trigger. To request more options, please file an issue.

target : '#primary_modal'

The target option should contain the ID or class of the modal dialog (the window that pops up).

trigger : '#primary_modal_trigger'

The trigger option should contain the ID or class of modal trigger (the clicked element that opens the modal)

callback

Accepts a function that will be executed upon completion.

Browser Compatibility

Feature Chrome Firefox Internet Explorer Safari
Basic Support Latest Latest 9+ 5.1+

Resources