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-index
in the example below) will need atransition-length
of0
and atransition-delay
property 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()
, wheremodal
is 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} isOpen
Returns true if the modal is open.
-
{Node} current
The DOM node currently displayed in the modal. Returns
null
if not set. -
{Function} close()
The modal's callable
close
method. -
{Function} open(String)
The modal's callable
open
method. 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} modal
The 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} modalInner
The inner container of the modal. This usually houses at least a close button (see HTML above). It should also contain the
modalContent
element. -
{String} modalContent
The container used to house the modal's content when it's transferred to the modal. This should always be a child of
modalInner
. -
{String} open
The 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} close
As above, except replace
open()
withclose()
, turn around three times, and pat yourself on the head. -
{String} page
A single outermost DOM selector to apply the
loadClass
andclass
classes to. This isbody
by default but could just as easily behtml
ormain
in any common web app. -
{String} loadClass
The class to apply to the
page
DOM node at the moment the script loads. -
{String} class
The class to apply to the
parent
container when the modal is open. -
{Boolean} clickOutside
If 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 theclose
query selector (default:[rel="modal:close"]
). -
{Boolean|Number} closeKey
If set to a keycode, hitting that keycode while the modal is open will fire a
close()
event. Set tofalse
to disable. -
{Boolean} transitions
If set to
false
, the modal will treat every browser like IE 9 and ignore transitions when opening and closing. -
{Function} onBeforeOpen
A function hook to fire before opening. This function is bound to the modal instance.
-
{Function} onBeforeClose
A function hook to fire before closing. This function is bound to the modal instance.
-
{Function} onOpen
A function hook to fire on opening. This function is bound to the modal instance.
-
{Function} onClose
A 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).