hey.js is a simple dependency-free modal written in JavaScript.
- Accessible (TODO).
- Lightweight.
- Flexible - works with inline content, dynamic content or AJAX'd content (TODO).
- No jQuery dependency.
- Great default styles that gracefully take care of scrollbar shifting and overflow issues.
There are loads of great modals out there, such as Modaal.
However most don't address the little UI annoyances that plague modals, such as the 'scrollbar shift' when applying overflow: hidden
to body.
Supports all recent versions of major browsers out of the box (IE10 and up). IE9 support requires a classList polyfill.
Install hey via NPM/Yarn:
// Yarn
yarn add hey.js
// NPM
npm install --save hey.js
You can include hey via a module bundler, such as Webpack:
// JS
import hey from 'hey.js';
Or just include the script directly:
<!-- HTML -->
<script src="myPath/js/heyModal.min.js"></script>
You'll also need to include the base stylesheet, and optionally a theme. You can import them as part of your build process:
// SASS
@import '../../node_modules/hey.js/dist/css/hey.css';
@import '../../node_modules/hey.js/dist/css/hey-minimal.css';
Or include them directly:
<!-- HTML -->
<link rel="stylesheet" href="myPath/css/hey.css">
<link rel="stylesheet" href="myPath/css/hey-minimal.css">
All below methods require manual initialization by passing in the trigger (link/button), like so:
heyModal(document.querySelector('.modal-trigger'))
If you have multiple modals with the same class you'll need to loop over and initialize each:
var myModals = document.querySelectorAll('.js-modal-trigger');
for (var i = 0; i < myModals.length; i++) {
heyModal(myModals[i]);
}
hey.js
generates the markup it needs to create accessible modals, without you having to worry about copying and pasting markup.
As long as you use the appropriate data
attributes, hey.js
will dynamically create a modal with your in-page content, then remove the old version from the DOM.
You can include an 'inline' modal on the page like so:
<!-- This is the 'link' that will open the modal -->
<a class="great-modal-trigger" data-hey=".great-modal">Modal link</a>
<!-- This is the modal itself -->
<div class="great-modal" style="display: none;">
<h3 data-hey-title>Modal title</h3>
<div data-hey-body>This is a modal and the contents</div>
<div data-hey-footer></div>
</div>
Then initialise it like so:
const myModal = heyModal(document.querySelector('.great-modal-trigger'));
You may want to use hey.js
as a confirm prompt for a link - for instance, clicking on link that performs a dangerous action:
<a href="/delete-post">Delete</a>
You can do this by creating an inline modal and using the data-hey attribute:
<!-- The modal trigger -->
<a
data-hey="#great-modal"
href="/delete"
class="modal-trigger button"
>
Delete post
</a>
<!-- The modal target -->
<div id="great-modal" style="display: none;">
<h3 data-hey-title>Delete post</h3>
<div data-hey-body>
<p>This is a modal and the contents</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis metus est, eu aliquet arcu
interdum eu. Mauris in tortor semper, pulvinar nunc et, tincidunt lectus. Donec erat ex, ultricies sit</p>
<!-- Manually include a confirm link in the body -->
<a href="/delete">Delete</a>
<!-- Include a close button by adding the 'data-hey-close' attribute -->
<button data-hey-close>Cancel</button>
</div>
</div>
However, hey.js
also provides a simpler alternative. You can omit the modal target altogether, and have hey.js
generate it:
<!-- The modal trigger, no need to provide a target -->
<a
data-hey-confirm
data-hey-title="Confirm"
data-hey-body="Are you sure?"
href="/delete"
class="modal-trigger button"
>
Delete post
</a>
Simply add the data-hey-confirm
attribute along with data-hey-title
and data-hey-body
. The confirm link will automatically be the target link.
This works well when there are a lot of links on the page that would need modals, and where it is impractical to produce the markup manually. The downside is that this approach is less flexible - there is no way to include HTML in the body of the modal.
If you're using an inline modal, only the data-hey
attribute is required.
If you're generating a confirm modal, the data-hey-title
, data-hey-body
and data-hey-confirm
attributes are all required.
Attribute | Description |
---|---|
data-hey | The class/id of the modal target (optional). |
data-hey-title | The title of the modal (optional). |
data-hey-body | The main content of the modal (optional). |
data-hey-confirm | Generates confirm yes/no actions based on a link (optional). |
Attribute | Description |
---|---|
data-hey-title | The title of the modal, appearing in the header. |
data-hey-body | The main content/body of the modal. |
data-hey-close | If this element is clicked it will close the modal (optional). |
Your hey.js
modal has several methods once initialised (like so):
const myModal = heyModal(document.querySelector('.great-modal-trigger'));
Opens the modal manually:
myModal.open();
Closes the modal manually:
myModal.close();
Removes the modal and cleans up:
myModal.destroy();
hey.js
fires two custom events (heyOpen
and heyClose
) on the main modal element.
You can either add an event listener to the generated wrapper, e.g.:
myModal.comp.wrapper.addEventListener('heyOpen', () => {
console.log('open!');
});
Or you can use the included .on
helper method, which defaults to the wrapper
:
myModal.on('heyOpen', () => {
console.log('opening!');
});
The essential 'base' styles are in hey.css
. These should be included first and overridden as necessary.
It's worth noting that the modal close event, which is responsible for firing events and mitigating shifting scrollbars, happens when the transition is finished on the .modal
element. This means if the dialog has a separate transition, it should finish before the main modal's transition ends. If this isn't the case, the dialog will animate during (or after the scrollbar change), which will cause an unnecessary shift.