简体   繁体   中英

Making multiple accessible modal dialogs

I'm trying to build multiple accessible modal dialog boxes into a website I'm creating. I've been using the code found at the following link: https://github.com/ireade/accessible-modal-dialog . This works well for my purposes. The box is fully accessible to keyboard commands. But I need to have multiple dialog boxes at different points on the site, with different information in each box. Does anyone know how I might go about altering the JS to make this possible? I've tried, but I'm not great with JS and haven't had any luck. And as a bonus: do you know how I might animate this dialog to scroll/appear gradually on the screen? Thank you for any and all help!

The library would need a slight rewrite to make it truly reusable. However you can use the library as it is by:-

  1. adding an extra class to the button that opens the modal (so we can reference each button individually, this could also be an ID)
  2. adding an extra class to the dialog (so we can reference each dialog seperately)
  3. creating a new modal and adding event listeners for that new modal (also change the references slightly for the old modal).

I have included a fiddle below. In the JavaScript I have added comments where I have made changes (scroll to the bottom to see the JavaScript that was included within the HTML, it was the only way I could make this work as a fiddle, all the top JavaScript is just the library you referenced.).

Also notice in the HTML I added an extra button to open the second modal and add a second modal. Pay close attention to the classes on the buttons and the modals and how they relate to the JavaScript I have added comments to.

Any questions just ask.

The proper way.

To improve this library I would add a data-target="modalID" to the buttons and have this automatically wire things together.

Create a function (ie function modalInit() ) that would follow the following steps:

  1. look for all buttons with a certain class ( .open-dialog )
  2. look at its data-target (ID of the modal)
  3. create the modal ( new Dialog(IDofModalFromDataTarget, dialogOverlay); )
  4. add the event listeners. ( DialogYouJustCreated.addEventListeners('buttonThatWeFoundTheDataIdOn', '.close-dialog')

Might look scary but if you break it down into those steps it would be a great learning exercise and you would then make it so that you could add modals without any extra code in the future.

If you do decide to try this feel free to post any fiddles and I will help you.

Working Example for Two Dialogs.

 //Ignore this top part, scroll down to 'This is the page HTML' function Dialog(dialogEl, overlayEl) { this.dialogEl = dialogEl; this.overlayEl = overlayEl; this.focusedElBeforeOpen; var focusableEls = this.dialogEl.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]'); this.focusableEls = Array.prototype.slice.call(focusableEls); this.firstFocusableEl = this.focusableEls[0]; this.lastFocusableEl = this.focusableEls[ this.focusableEls.length - 1 ]; this.close(); // Reset } Dialog.prototype.open = function() { var Dialog = this; this.dialogEl.removeAttribute('aria-hidden'); this.overlayEl.removeAttribute('aria-hidden'); this.focusedElBeforeOpen = document.activeElement; this.dialogEl.addEventListener('keydown', function(e) { Dialog._handleKeyDown(e); }); this.overlayEl.addEventListener('click', function() { Dialog.close(); }); this.firstFocusableEl.focus(); }; Dialog.prototype.close = function() { this.dialogEl.setAttribute('aria-hidden', true); this.overlayEl.setAttribute('aria-hidden', true); if ( this.focusedElBeforeOpen ) { this.focusedElBeforeOpen.focus(); } }; Dialog.prototype._handleKeyDown = function(e) { var Dialog = this; var KEY_TAB = 9; var KEY_ESC = 27; function handleBackwardTab() { if ( document.activeElement === Dialog.firstFocusableEl ) { e.preventDefault(); Dialog.lastFocusableEl.focus(); } } function handleForwardTab() { if ( document.activeElement === Dialog.lastFocusableEl ) { e.preventDefault(); Dialog.firstFocusableEl.focus(); } } switch(e.keyCode) { case KEY_TAB: if ( Dialog.focusableEls.length === 1 ) { e.preventDefault(); break; } if ( e.shiftKey ) { handleBackwardTab(); } else { handleForwardTab(); } break; case KEY_ESC: Dialog.close(); break; default: break; } }; Dialog.prototype.addEventListeners = function(openDialogSel, closeDialogSel) { var Dialog = this; var openDialogEls = document.querySelectorAll(openDialogSel); for ( var i = 0; i < openDialogEls.length; i++ ) { openDialogEls[i].addEventListener('click', function() { Dialog.open(); }); } var closeDialogEls = document.querySelectorAll(closeDialogSel); for ( var i = 0; i < closeDialogEls.length; i++ ) { closeDialogEls[i].addEventListener('click', function() { Dialog.close(); }); } }; //*****************This is the page HTML*********************// var dialogOverlay = document.querySelector('.dialog-overlay'); //dialog overlay is used by both so we only need one reference to it here. var navDialogEl1 = document.querySelector('.dialog1');//grab the first dialog element var myDialog1 = new Dialog(navDialogEl1, dialogOverlay); //create a new dialog from the element 'navDialogEl1'. myDialog1.addEventListeners('.open-dialog1', '.close-dialog'); //notice how I changed the open dialog class - I also added an extra class to the button that is related to this dialog with the same name var navDialogEl2 = document.querySelector('.dialog2'); //grab the second dialog element var myDialog2 = new Dialog(navDialogEl2, dialogOverlay); //create a new dialog for the second dialog element, notice how I use the same background (dialogOverlay). myDialog2.addEventListeners('.open-dialog2', '.close-dialog'); //add an event listener to open this dialog. Yet again check the HTML I added an extra class to the second button 'open-dialog2'. Notice how I also used the same 'close-dialog' as any button with this calss should close all dialogs anyway.
 .dialog-overlay { z-index: 2; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.7); }.dialog { z-index: 3; background-color: #fff; padding: 20px; text-align: center; width: 90%; max-width: 400px; position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); }.dialog-overlay[aria-hidden="true"], .dialog[aria-hidden="true"] { display: none; }.dialog-overlay:not([aria-hidden="true"]), .dialog:not([aria-hidden="true"]) { display: block; }.sr-only { opacity: 0; position: absolute; clip: rect(1px 1px 1px 1px); clip: rect(1px, 1px, 1px, 1px); }
 <header> <div class="wrapper"> <h1><a href="https://ireade.github.io/accessible-modal-dialog/">Accessible Dialog</a></h1> <button type="button" aria-label="Open Navigation" class="open-dialog1">open 1</button> <button type="button" aria-label="Open Navigation" class="open-dialog2">open 2</button> </div> </header> <div class="dialog dialog1" role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-description"> <h1 id="dialog-title">Dialog 1</h1> <button type="button" aria-label="Close Navigation" class="close-dialog"> Close </button> </div> <div class="dialog dialog2" role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-description"> <h1 id="dialog-title">Dialog 2</h1> <button type="button" aria-label="Close Navigation" class="close-dialog"> Close</button> </div> <div class="wrapper body-wrapper"> <p><a href="https://github.com/ireade/accessible-modal-dialog">View Source</a> | <a href="=https://bitsofco.de/accessible-modal-dialog">Blog Post</a> <p>Venmo tacos ennui hoodie lomo tousled. Meh irony blue bottle brooklyn paleo. Post-ironic PBR&B blue bottle, iPhone meh ennui forage salvia normcore neutra chicharrones gentrify. Banjo jean shorts selfies, try-hard venmo before they sold out 8-bit gluten-free pinterest sustainable messenger bag you probably haven't heard of them poutine. Scenester farm-to-table craft beer, knausgaard leggings letterpress brunch asymmetrical. Brooklyn you probably haven't heard of them typewriter flannel. Etsy austin venmo, knausgaard green juice squid butcher kombucha literally beard jean shorts VHS tote bag.</p> <p>Artisan bushwick pop-up, biodiesel viral semiotics cliche pinterest fingerstache godard lo-fi franzen forage. Hammock narwhal ethical, kogi put a bird on it pork belly bushwick photo booth +1 master cleanse pinterest direct trade vegan tofu. Small batch cold-pressed paleo wolf, skateboard asymmetrical cred vegan pickled pinterest freegan. Man bun portland man braid, thundercats swag keffiyeh scenester semiotics put a bird on it keytar four loko beard pour-over. Meh VHS biodiesel actually poutine, normcore neutra beard narwhal hoodie. Synth sustainable cred meditation health goth tousled. Post-ironic cornhole scenester whatever, authentic bushwick keffiyeh venmo kinfolk chia.</p> <p>Sriracha XOXO master cleanse lomo blue bottle, banh mi fashion axe man braid flexitarian. Meggings pug ennui, chambray 8-bit celiac gentrify. Bitters direct trade chia semiotics. Synth fixie mixtape, health goth four dollar toast vinyl 3 wolf moon VHS schlitz. Drinking vinegar letterpress VHS poutine, venmo cronut distillery artisan. Everyday carry craft beer butcher DIY. Normcore affogato chillwave, thundercats banh mi fingerstache keytar pop-up four loko four dollar toast.</p> </div> <div class="dialog-overlay" tabindex="-1"></div> <!--JavaScript moved from here to the bottom of the JavaScript section-->

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM