Written in clean ECMAScript 6 and transpiled using 6to5.
MIT. Please feel free to offer any input - pull requests, bug tracking, suggestions are all welcome.
That's not a question and this is not the script you're looking for. It is licensed under the MIT License though, so if you'd like to base a jQuery plugin on it, feel free to do so. Just remember that losing native DOM bindings means losing speed, too.
Because of the bloat of DOM libraries. Because of the dreadful performance of monolithic JavaScript frameworks. Because decoupled is the way to go. Because standard JavaScript provides everything you need for this task. Because sometimes, a 7KB minified (1.8KB gzipped) script is all you need. Also because sometimes you're adding this to an already glorious JavaScript overhead, e.g. 97 gzipped kilobytes of Ember.js.
Great though CSS Modal (and similar solutions) are, developers may encounter problems when building a stateful UI, as using the CSS :target pseudo-class invariably means changing the window's location.hash property. This can cause havoc with client-side routers, as well as obfuscate the modal on the offchance that any anchor inside it changes the window's hash.
Not to worry. open and close event listeners are delegated so the modal script will keep running irrespective of whether you're using a client-side router. If you're desperate for garbage collection (e.g. if your app's made from last week's haddock surprise), you might be pleased to know there's a destroy method baked into the modal too.
-
The script can be installed from NPM and included using Browserify:
Command line:
npm install --save-dev vanilla-modal
JavaScript:
var VanillaModal = require('vanilla-modal');
-
Browserify (without NPM), Webpack and CommonJS aficionados get to use the following line:
var VanillaModal = require('/path/to/vanilla-modal');`
-
For RequireJS, Webpack AMD and similar asynchronous module loaders, use:
require(['/path/to/vanilla-modal'], function(VanillaModal) { ... });
-
Or, if you just can't bear to be fancy:
<script src="/path/to/vanilla-modal.js"></script>
It's as simple as typing:
var modal = new VanillaModal(opts);...where opts is a hash of settings to supply the constructor with on instantiation.-
This part is important. Vanilla Modal doesn't use any fancy string interpolation or template syntax. You'll need some good, solid elbow grease to build up your modal's layout in the DOM. The payoff? You can make the modal look like anything you want.
<div class="modal">
<div class="modal-inner">
<a rel="modal:close">Close</a>
<div class="modal-content"></div>
</div>
</div>Next, add your modal content to hidden containers on the page. The modal will inline the contents inside the selected container.
<!--
Give each one an ID attribute. It's totally possible to have
more than one modal per page, and where they live in the DOM
doesn't matter. Just remember that their innerHTML will be
hauled out of its container and inlined into the modal.
-->
<div id="modal-1" style="display:none;">Modal 1 content</div>
<div id="modal-2" style="display:none;">Modal 2 content</div>You nutty professor, you.
Forget choppy UI animations and JavaScript modal display parameters. Vanilla Modal keeps display specifications where they belong: in stylesheets. Hardware acceleration optional, but recommended, as is the liberal use of vw, vh and calc units to win friends and influence people.
The only things to remember here are:
- Using
display: none;will get rid of any transitions you might otherwise be using. - Whatever property you're using to obfuscate the modal (
z-indexin the example below) will need atransition-lengthof0and atransition-delayproperty of the length of the other transitions. For example:
transition: opacity 0.2s, z-index 0s 0.2s;Only two HTML delegates affect the modal. By default:
[rel="modal:open"]maps tomodal.open()and[rel="modal:close]maps tomodal.close(), wheremodalis the VanillaModal instance name.
<a href="#modal-1" rel="modal:open">Modal 1</a>...will open #modal-1 inside the modal, while...
<a rel="modal:close">Close</a>...will close the modal.
The defaults can be changed at instantiation:
var modal = new VanillaModal({ open : '.my-open-class', close : '.my-close-class' });If you need to flash a modal on screen for any reason, it can be done by passing a DOM selector string to the the open() function.
For example:
var modal = new VanillaModal();
// Flashes a message on the screen to annoy people.
modal.open('#psa');
// Closes the modal while they're still looking for the close button.
setTimeout(function() {
modal.close();
}, 2000);...although this is a truly evil practice and should be avoided on pain of dismemberment.
-
{Object} $The DOM nodes used for the modal.
-
{Object} $$The modal's settings object.
-
{Boolean} isOpenReturns true if the modal is open.
-
{Node} currentThe DOM node currently displayed in the modal. Returns
nullif not set. -
{Function} close()The modal's callable
closemethod. -
{Function} open(String)The modal's callable
openmethod. Requires an existing DOM selector string. -
{Function} destroy()Closes the modal and removes all event listeners.
The options object contains DOM selector strings and bindings. It can be overridden at instantiation by providing an options object to new VanillaModal(options).
The API is feature-frozen for the version 1.x.x branch.
{
modal : '.modal',
modalInner : '.modal-inner',
modalContent : '.modal-content',
open : '[rel="modal:open"]',
close : '[rel="modal:close"]',
page : 'body',
loadClass : 'vanilla-modal',
class : 'modal-visible',
clickOutside : false,
closeKey : 27,
transitions : true,
onBeforeOpen : function() {},
onBeforeClose : function() {},
onOpen : function() {},
onClose : function() {}
}-
{String} modalThe class of the outer modal container. This is usually a fixed position element that takes up the whole screen. It doesn't have to be, though - the modal can just as easily be a discreet bar that pops out from the corner of the screen.
-
{String} modalInnerThe inner container of the modal. This usually houses at least a close button (see HTML above). It should also contain the
modalContentelement. -
{String} modalContentThe container used to house the modal's content when it's transferred to the modal. This should always be a child of
modalInner. -
{String} openThe selector to bind the
open()event to. This can be anything. I'd recommend using the default as it's generic and keeps code legible. -
{String} closeAs above, except replace
open()withclose(), turn around three times, and pat yourself on the head. -
{String} pageA single outermost DOM selector to apply the
loadClassandclassclasses to. This isbodyby default but could just as easily behtmlormainin any common web app. -
{String} loadClassThe class to apply to the
pageDOM node at the moment the script loads. -
{String} classThe class to apply to the
parentcontainer when the modal is open. -
{Boolean} clickOutsideIf set to
true, a click outside the modal will fire aclose()event. Otherwise, the only ways to close the modal are to hit[esc]or click an item covered by theclosequery selector (default:[rel="modal:close"]). -
{Boolean|Number} closeKeyIf set to a keycode, hitting that keycode while the modal is open will fire a
close()event. Set tofalseto disable. -
{Boolean} transitionsIf set to
false, the modal will treat every browser like IE 9 and ignore transitions when opening and closing. -
{Function} onBeforeOpenA function hook to fire before opening. This function is bound to the modal instance.
-
{Function} onBeforeCloseA function hook to fire before closing. This function is bound to the modal instance.
-
{Function} onOpenA function hook to fire on opening. This function is bound to the modal instance.
-
{Function} onCloseA function hook to fire on closing. This function is bound to the modal instance. I just cheated & copy-pasted the last few lines.
This script works in the evergreen mobile & desktop browsers, IE 9 and above, and frankly doesn't give two hoots about Blackberry or any prior versions of IE (read: they're un-tested, but feel free to test, fork and shim).