Author: | tomaszbujnowicz |
---|---|
Views Total: | 9,311 views |
Official Page: | Go to website |
Last Update: | May 1, 2020 |
License: | MIT |
Preview:

Description:
A dead simple vanilla JavaScript sliding drawer component designed for off-canvas menus, settings panels, sidebar notifications and much more.
How to use it:
1. Create the HTML for the drawer.
<section class="drawer" id="drawer-name" data-drawer-target> <div class="drawer__overlay" data-drawer-close tabindex="-1"></div> <div class="drawer__wrapper"> <div class="drawer__header"> <div class="drawer__title"> Drawer Title Here </div> <button class="drawer__close" data-drawer-close aria-label="Close Drawer"></button> </div> <div class="drawer__content"> Drawer Content Here </div> </div> </section>
2. Hide the drawer on page load.
.drawer { display: none; }
3. The main CSS for the drawer.
.drawer__header { padding: 1.5rem; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #ddd; } .drawer__close { margin: 0; padding: 0; border: none; background-color: transparent; cursor: pointer; background-image: url("data:image/svg+xml,%0A%3Csvg width='15px' height='16px' viewBox='0 0 15 16' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cg id='Page-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='2.-Menu' transform='translate(-15.000000, -13.000000)' stroke='%23000000'%3E%3Cg id='Group' transform='translate(15.000000, 13.521000)'%3E%3Cpath d='M0,0.479000129 L15,14.2971819' id='Path-3'%3E%3C/path%3E%3Cpath d='M0,14.7761821 L15,-1.24344979e-14' id='Path-3'%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); width: 15px; height: 15px; } .drawer__wrapper { position: fixed; top: 0; right: 0; bottom: 0; height: 100%; width: 100%; max-width: 500px; z-index: 9999; overflow: auto; transition: transform 0.3s; will-change: transform; background-color: #fff; display: flex; flex-direction: column; -webkit-transform: translateX(103%); transform: translateX(103%); /* extra 3% because of box-shadow */ -webkit-overflow-scrolling: touch; /* enables momentum scrolling in iOS overflow elements */ box-shadow: 0 2px 6px #777; } .drawer__content { position: relative; overflow-x: hidden; overflow-y: auto; height: 100%; flex-grow: 1; padding: 1.5rem; } .drawer.is-active { display: block; } .drawer.is-visible .drawer__wrapper { -webkit-transform: translateX(0); transform: translateX(0); } .drawer.is-visible .drawer__overlay { opacity: 0.5; }
4. Style the background overlay when the drawer is opened.
.drawer__overlay { position: fixed; top: 0; right: 0; bottom: 0; left: 0; width: 100%; z-index: 200; opacity: 0; transition: opacity 0.3s; will-change: opacity; background-color: #000; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
5. Create a trigger element to slide the drawer out from the right side of the screen.
<a href="#" data-drawer-trigger aria-controls="drawer-name" aria-expanded="false">Open Drawer</a>
6. The main JavaScript to enable the drawer.
var drawer = function () { /** * Element.closest() polyfill * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill */ if (!Element.prototype.closest) { if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } Element.prototype.closest = function (s) { var el = this; var ancestor = this; if (!document.documentElement.contains(el)) return null; do { if (ancestor.matches(s)) return ancestor; ancestor = ancestor.parentElement; } while (ancestor !== null); return null; }; } // // Settings // var settings = { speedOpen: 50, speedClose: 350, activeClass: 'is-active', visibleClass: 'is-visible', selectorTarget: '[data-drawer-target]', selectorTrigger: '[data-drawer-trigger]', selectorClose: '[data-drawer-close]', }; // // Methods // // Toggle accessibility var toggleccessibility = function (event) { if (event.getAttribute('aria-expanded') === 'true') { event.setAttribute('aria-expanded', false); } else { event.setAttribute('aria-expanded', true); } }; // Open Drawer var openDrawer = function (trigger) { // Find target var target = document.getElementById(trigger.getAttribute('aria-controls')); // Make it active target.classList.add(settings.activeClass); // Make body overflow hidden so it's not scrollable document.documentElement.style.overflow = 'hidden'; // Toggle accessibility toggleccessibility(trigger); // Make it visible setTimeout(function () { target.classList.add(settings.visibleClass); }, settings.speedOpen); }; // Close Drawer var closeDrawer = function (event) { // Find target var closestParent = event.closest(settings.selectorTarget), childrenTrigger = document.querySelector('[aria-controls="' + closestParent.id + '"'); // Make it not visible closestParent.classList.remove(settings.visibleClass); // Remove body overflow hidden document.documentElement.style.overflow = ''; // Toggle accessibility toggleccessibility(childrenTrigger); // Make it not active setTimeout(function () { closestParent.classList.remove(settings.activeClass); }, settings.speedClose); }; // Click Handler var clickHandler = function (event) { // Find elements var toggle = event.target, open = toggle.closest(settings.selectorTrigger), close = toggle.closest(settings.selectorClose); // Open drawer when the open button is clicked if (open) { openDrawer(open); } // Close drawer when the close button (or overlay area) is clicked if (close) { closeDrawer(close); } // Prevent default link behavior if (open || close) { event.preventDefault(); } }; // Keydown Handler, handle Escape button var keydownHandler = function (event) { if (event.key === 'Escape' || event.keyCode === 27) { // Find all possible drawers var drawers = document.querySelectorAll(settings.selectorTarget), i; // Find active drawers and close them when escape is clicked for (i = 0; i < drawers.length; ++i) { if (drawers[i].classList.contains(settings.activeClass)) { closeDrawer(drawers[i]); } } } }; // // Inits & Event Listeners // document.addEventListener('click', clickHandler, false); document.addEventListener('keydown', keydownHandler, false); }; drawer();
7. Slide the drawer out from the left side instead.
<section class="drawer drawer--left" id="drawer-name" data-drawer-target> ... </section>
.drawer--left .drawer__wrapper { left: 0; right: auto; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); }
Changelog:
05/02/2020
- Use translate3d instead of translateX
04/18/2020
- Minor adjustments