Dialog (Message Dialog)

Dialog (Message Dialog)

This page shows a message modal pattern using the (role="dialog") ARIA attribute. A modal is a dialog box/popup window that is displayed on top of the current page and requires a user action to close it. The dialog is only available to users when the modal is active. When the modal is active, the rest of the page is unavailable by mouse, keyboard, touch, or screen reader.



Turn on a screen reader to experience this example in action.

Message Dialog

This is the description for the dialog

Message dialogs can contain long (or short) passages of text, such as terms of use notices, user agreements for software, help text, explanations, etc.

Initial HTML Markup

<div class="deque-dialog-message" id="deque-dialog-message" data-is-modal="true" data-tabtrap  data-id="first-deque-dialog-message">
  <div class="deque-dialog-screen-wrapper"></div>
  <div class="deque-dialog-screen">
    <h1 id="dialogMessageHeading" class="deque-dialog-heading" tabindex="-1">Message Dialog</h1>
    <p id="dialogMessageDescription" class="deque-dialog-description">This is the description for the dialog</p>
    <div role="document" class="deque-dialog-content">
      <p>Message dialogs can contain long (or short) passages of text, such as terms of use notices, user agreements for software, help text, explanations, etc.</p>
    </div>
    <p class="deque-dialog-buttons">
      <button class="deque-button deque-dialog-button-submit">Continue</button>
      <button class="deque-button deque-dialog-button-cancel">Cancel</button>
      <button class="deque-dialog-button-close" aria-label="Close dialog"><span aria-hidden="true"></span></button>
    </p>
  </div>
</div>

<div>
  <button id="deque-dialog-message-trigger" class="deque-dialog-message-trigger deque-button" aria-controls="deque-dialog-message"  data-id="first-deque-dialog-message">Show Message Dialog!</button>
</div>

JavaScript

Required: The complete JavaScript file (for all patterns in the library): deque-patterns.min.js

Key parts of the JavaScript file

Note: The code below is functional only in the context of the complete JavaScript file.

In the @dialog section:



      //import {createContentArea} from './components/contentArea';
      function createDialog(id, role) {
        var screen = (0, _lightboxScreen.createScreen)();
        var alert = document.getElementById(id);
        var dialogButtons = alert.querySelector('.deque-dialog-buttons');
        var buttons = dialogButtons.querySelectorAll('button');
        for (var x = 0; x < buttons.length; x++) {
          buttons[x].addEventListener('click', hide);
        }

        // if (document.getElementById('fullContainer')) {
        //   document.getElementById('fullContainer').setAttribute('role', 'presentation');
        // }

        // close button
        var xButton = document.createElement('span');

        function setInitialFocus(config) {
          if (!config.isAlert) {
            var target = (0, _focusUtils.getFirstFocusableChild)(alert);
            if (target.classList.contains('deque-dialog-button-close')) {
              target = (0, _focusUtils.getNextFocusableChild)(alert, target);
            }

            if (target) {
              return target.focus();
            }
          }

          if (config.isAlert && config.isDetail) {
            //return content.focus();
          }

          if (buttonBar.getFirstButton()) { }
          //return buttonBar.getFirstButton().focus();


          //alert.focus();
          if (alert.querySelector('.deque-dialog-screen').classList.contains('imageMagnifier')) {
            alert.querySelector('.deque-dialog-content').focus();
          } else {
            alert.querySelector('.deque-dialog-screen').focus();
          }

          alert.querySelector('.deque-dialog-heading').focus();
        }

        function reset() {
          clearClasses();
          screen.clear();
        }

        function addClasses(classes) {
          if (classes.isArray) {
            classes.forEach(function (item) {
              return alert.classList.add(item);
            });
          } else {
            alert.classList.add(classes);
          }
        }

        function clearClasses() {
          var toRemove = [];
          for (var i = 0; i < alert.classList.length; i++) {
            toRemove.push(alert.classList[i]);
          }

          toRemove.forEach(function (c) {
            alert.classList.remove(c);
          });

          addClasses(role);
        }

        function setRole(role) {
          alert.setAttribute('role', role);
        }

        function hideCloseButton() {
          xButton.classList.add('deque-hidden');
        }

        function showCloseButton() {
          xButton.classList.remove('deque-hidden');
        }

        //var content = createContentArea(alert);

        var returnFocusTo;

        xButton.addEventListener('click', handleEscape);

        var buttonBar = alert.querySelector('.deque-dialog-buttons');
        buttonBar = (0, _buttonBar.createButtonBar)(buttonBar);

        function show(config) {
          if (config.classes) {
            addClasses(config.classes);
          }

          if (config.describedby) {
            //alert.setAttribute('aria-describedby', config.describedby);
          }

          if (config.labelledby) {
            //alert.setAttribute('aria-labelledby', config.labelledby);
          }

          if (config.hideCloseButton) {
            hideCloseButton();
          } else {
            showCloseButton();
          }

          if (config.wrapperID) {
            document.getElementById(config.wrapperID).setAttribute('aria-hidden', 'true');
          }

          config.isAlert ? setRole('alertdialog') : setRole('dialog');
          screen.show();
          document.body.appendChild(alert);
          alert.setAttribute('aria-hidden', 'false');
          alert.classList.remove('deque-hidden');
          alert.classList.add('deque-show-block');

          if (alert.querySelector('.deque-dialog-screen').classList.contains('imageMagnifier')) {
            alert.querySelector('.deque-dialog-content').setAttribute('tabindex', '0');
          } else {
            alert.querySelector('.deque-dialog-screen').setAttribute('tabindex', '0');
          }

          setInitialFocus(config);
        }

        function hide() {
          if (alert.hasAttribute('aria-describedby')) {
            alert.removeAttribute('aria-describedby');
          }

          reset();
          alert.setAttribute('aria-hidden', 'true');
          alert.classList.add('deque-hidden');

          returnFocusTo.focus();
        }

        function handleEscape() {
          hide();
        }

        function keyUpHandler(e) {
          if (e.which === 27) {
            handleEscape();
            e.stopPropagation();
          }
        }

        alert.addEventListener('keyup', keyUpHandler);

        (0, _focusUtils.initTabTrap)(alert);

        return function (triggerElement, config) {
          returnFocusTo = triggerElement;
          // make sure we never end up with a case where a non-alert box is treated
          // as a simple alert.
          if (!config.isAlert) {
            config.isDetail = true;
          }

          show(config);
        };
      }

      var activateHander = false;

      var activateDequeDialogButtonClickHandlers = function activateDequeDialogButtonClickHandlers() {
        var bodyChilds = document.body.children;
        //var dequeDialogMessageAlert = document.querySelector('.deque-dialog-message-alert') || null;
        //var dequeDialogMessage = document.querySelector('.deque-dialog-message') || null;
        //var dequeDialogAlert = document.querySelector('.deque-dialog-alert') || null;
        //var dequeDialog = document.querySelector('.deque-dialog') || null;
        var dequeDialogBackgroundLayer = document.querySelectorAll('.deque-dialog-screen-wrapper') || null;
        var dequeDialogCloseButton = document.querySelectorAll('.deque-dialog-button-cancel') || null;

        var ariaHiddenList = null;
        var ariaHiddenFalseList = null;
        var ariaHiddenTrueList = null;
        var triggerNode = null;

        var dequeJsAria = 'deque-js-aria';
        var dequeJsAriaTrue = 'deque-js-aria-true';
        var dequeJsAriaFalse = 'deque-js-aria-false';

        /*
        var triggerList = [document.querySelector('#deque-dialog-message-alert-trigger'), document.querySelector('#deque-dialog-message-trigger'), document.querySelector('#deque-dialog-alert-trigger'), document.querySelector('#deque-dialog-trigger')];
        */

        if (document.querySelector('#deque-dialog-message-alert-trigger') || document.querySelector('#deque-dialog-message-trigger') || document.querySelector('#deque-dialog-alert-trigger') || document.querySelector('#deque-dialog-trigger')) {
          [].slice.call(document.querySelectorAll('#deque-dialog-message-alert-trigger, #deque-dialog-message-trigger, #deque-dialog-alert-trigger, #deque-dialog-trigger')).forEach(function (triggerBtn) {
            triggerBtn.addEventListener('click', function (e) {
              triggerNode = e.currentTarget;

              [].slice.call(bodyChilds).forEach(function (node) {
                //if(node != dequeDialogMessageAlert && node != dequeDialogMessage && node != dequeDialogAlert && node != dequeDialog && (node.nodeName).toLowerCase() != 'link' && (node.nodeName).toLowerCase() != 'script') {
                if (node.getAttribute('data-id') != triggerNode.getAttribute('data-id')) {
                  var nodeAriaHidden = node.getAttribute('aria-hidden');
                  if (!(node.classList.contains(dequeJsAria) || node.classList.contains(dequeJsAriaTrue) || node.classList.contains(dequeJsAriaFalse))) {
                    if (!nodeAriaHidden) {
                      node.classList.add(dequeJsAria);
                    } else if (nodeAriaHidden == 'true') {
                      node.classList.add(dequeJsAriaTrue);
                    } else if (nodeAriaHidden == 'false') {
                      node.classList.add(dequeJsAriaFalse);
                    }
                  }
                }
                //}
              });

              var allAriaHiddenList = document.querySelectorAll('.' + dequeJsAria + ', .' + dequeJsAriaTrue + ', .' + dequeJsAriaFalse);
              [].slice.call(allAriaHiddenList).forEach(function (ariaNode) {
                ariaNode.setAttribute('aria-hidden', 'true');
              });

              ariaHiddenList = document.querySelectorAll('.' + dequeJsAria);
              ariaHiddenFalseList = document.querySelectorAll('.' + dequeJsAriaFalse);
              ariaHiddenTrueList = document.querySelectorAll('.' + dequeJsAriaTrue);
            });
          });

          setTimeout(function () {

            if (document.querySelector('.deque-dialog-screen').classList.contains('imageMagnifier')) {
              document.querySelector('.deque-dialog-content').setAttribute('tabindex', '0');
              document.querySelector('.deque-dialog-content').focus();
            } else {
              document.querySelector('.deque-dialog-screen').setAttribute('tabindex', '0');
              document.querySelector('.deque-dialog-screen').focus();
            }
          }, 1000);
        }

        var dequeCloseBtnList = document.querySelectorAll('.deque-dialog-button-close');

        if (dequeCloseBtnList.length > 0) {
          [].slice.call(dequeCloseBtnList).forEach(function (btn) {
            btn.addEventListener('click', function () {
              if (ariaHiddenList) {
                [].slice.call(ariaHiddenList).forEach(function (ariaNode) {
                  ariaNode.removeAttribute('aria-hidden');
                  ariaNode.classList.remove(dequeJsAria);
                });
              }

              if (ariaHiddenFalseList) {
                [].slice.call(ariaHiddenFalseList).forEach(function (ariaNode) {
                  ariaNode.setAttribute('aria-hidden', 'false');
                  ariaNode.classList.remove(dequeJsAriaFalse);
                });
              }

              if (ariaHiddenTrueList) {
                [].slice.call(ariaHiddenTrueList).forEach(function (ariaNode) {
                  ariaNode.setAttribute('aria-hidden', 'true');
                  ariaNode.classList.remove(dequeJsAriaTrue);
                });
              }
            });
          });
        }

        var dequeSubmitBtnList = document.querySelectorAll('.deque-dialog-button-submit');
        if (dequeSubmitBtnList.length > 0) {
          [].slice.call(dequeSubmitBtnList).forEach(function (btn) {
            btn.addEventListener('click', function (e) {
              e.preventDefault();
              if (ariaHiddenList) {
                [].slice.call(ariaHiddenList).forEach(function (ariaNode) {
                  ariaNode.removeAttribute('aria-hidden');
                  ariaNode.classList.remove(dequeJsAria);
                });
              }

              if (ariaHiddenFalseList) {
                [].slice.call(ariaHiddenFalseList).forEach(function (ariaNode) {
                  ariaNode.setAttribute('aria-hidden', 'false');
                  ariaNode.classList.remove(dequeJsAriaFalse);
                });
              }

              if (ariaHiddenTrueList) {
                [].slice.call(ariaHiddenTrueList).forEach(function (ariaNode) {
                  ariaNode.setAttribute('aria-hidden', 'true');
                  ariaNode.classList.remove(dequeJsAriaTrue);
                });
              }

              if (dequeActiveDialogButton) {
                dequeActiveDialogButton.focus();
              }
            });
          });
        }

        /* closing popup on keypress (ESC, etc.,)  and on clicking of background black layer */
        var KEY_CONFIG = {
          27: 'ESC'
          //16: 'SHIFT'
        };

        document.body.addEventListener('keydown', function (e) {
          for (var key in KEY_CONFIG) {
            if (key == e.keyCode) {
              inPageCloseAction();
            }
          }
        });

        var inPageCloseAction = function inPageCloseAction(bgLayer) {
          if (bgLayer) {
            bgLayer.parentNode.querySelector('.deque-dialog-button-close').click(); /* code to close the popup */
          } else {
            [].slice.call(document.querySelectorAll('.deque-dialog-button-close')).forEach(function (btnClose) {
              btnClose.click();
            });
          }
          [].slice.call(dequeCloseBtnList).forEach(function (closeBtn) {
            closeBtn.click();
          });

          if (triggerNode) {
            triggerNode.focus(); /* code  to retain focus to the trigger button */
          }
        };

        if (dequeDialogBackgroundLayer) {
          [].slice.call(dequeDialogBackgroundLayer).forEach(function (bgLayer) {
            bgLayer.addEventListener('click', function () {
              inPageCloseAction(bgLayer);
            });
          });
        }

        if (dequeDialogCloseButton) {
          [].slice.call(dequeDialogCloseButton).forEach(function (clsBtn) {
            clsBtn.addEventListener('click', function () {
              inPageCloseAction(clsBtn);
            });
          });
        }
      };

      var dequeActiveDialogButton = null;

      /*
      * activateAllDialogs(): This method has 4 types of Dialogs.
      * Simple Dialogs, Dialog Alerts, Dialog Messages and Dialog Messages Alerts
      * 1. Looks for all instances of respective classes and loops them over 
      * with all details like description, headings and stores them in config class.
      * 2. For each button click, it gets the value of aria-control and creates and shows the respective dialog based on the config values.
      */
      function activateAllDialogs() {

        //activate all simple Dialogs
        var dialogs = document.querySelectorAll('.deque-dialog');

        for (var i = 0; i < dialogs.length; i++) {
          dialogs[i].classList.add('deque-hidden');

          var dialogDataId = '_' + dialogs[i].getAttribute('data-id');
          //dialogs[i].setAttribute('id', dialogs[i].getAttribute('id') + dialogDataId);
          document.querySelector('button[data-id="' + dialogs[i].getAttribute('data-id') + '"]').setAttribute('aria-controls', dialogs[i].getAttribute('id'));

          var dialogHeadingElement = dialogs[i].querySelector('.deque-dialog-heading');
          dialogHeadingElement.setAttribute('id', dialogHeadingElement.getAttribute('id') + dialogDataId);

          var dialogDescriptionElement = dialogs[i].querySelector('.deque-dialog-description');
          dialogDescriptionElement.setAttribute('id', dialogDescriptionElement.getAttribute('id') + dialogDataId);

          var dialogDescription;
          var dialogLabel;

          var configDialog = {
            describedby: dialogDescription,
            labelledby: dialogLabel,
            isAlert: false
          };

          var triggerDialog = document.getElementsByClassName('deque-dialog-trigger deque-button');

          triggerDialog[i].addEventListener('click', function (event) {
            event.preventDefault();
            dequeActiveDialogButton = triggerDialog[i];
            var attributeDialog = this.getAttribute('aria-controls');
            var showDialog = createDialog(attributeDialog, 'deque-dialog');

            var dequeDialogWidgetElement = document.querySelectorAll('.deque-dialog[data-id="' + event.currentTarget.getAttribute('data-id') + '"]')[0];
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-heading')) {
              configDialog.describedby = dequeDialogWidgetElement.querySelector('.deque-dialog-heading').getAttribute('id');
            } else {
              configDialog.describedby = '';
            }
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-description')) {
              configDialog.labelledby = dequeDialogWidgetElement.querySelector('.deque-dialog-description').getAttribute('id');
            } else {
              configDialog.labelledby = '';
            }

            if (dequeDialogWidgetElement.querySelector('#nameInput')) {
              var nameInputElement = dequeDialogWidgetElement.querySelector('#nameInput');
              var labelInputElement = dequeDialogWidgetElement.querySelector('label[for=' + nameInputElement.getAttribute('id') + ']');
              var modifiedNameInputElementId = nameInputElement.getAttribute('id') + '_' + event.currentTarget.getAttribute('data-id');
              labelInputElement.setAttribute('for', modifiedNameInputElementId);
              nameInputElement.setAttribute('id', modifiedNameInputElementId);
            }

            if (dequeDialogWidgetElement.querySelector('#lastNameInput')) {
              var lastNameInputElement = dequeDialogWidgetElement.querySelector('#lastNameInput');
              var labelLastInputElement = dequeDialogWidgetElement.querySelector('label[for=' + lastNameInputElement.getAttribute('id') + ']');
              var modifiedLastNameInputElementId = lastNameInputElement.getAttribute('id') + '_' + event.currentTarget.getAttribute('data-id');
              labelLastInputElement.setAttribute('for', modifiedLastNameInputElementId);
              lastNameInputElement.setAttribute('id', modifiedLastNameInputElementId);
            }

            showDialog(this, configDialog);
          });
        }

        //activate all dialog alerts  
        var dialogAlerts = document.querySelectorAll('.deque-dialog-alert');
        for (var j = 0; j < dialogAlerts.length; j++) {
          dialogAlerts[j].classList.add('deque-hidden');

          dialogDataId = '_' + dialogAlerts[j].getAttribute('data-id');
          dialogAlerts[j].setAttribute('id', dialogAlerts[j].getAttribute('id') + dialogDataId);
          document.querySelector('button[data-id="' + dialogAlerts[j].getAttribute('data-id') + '"]').setAttribute('aria-controls', dialogAlerts[j].getAttribute('id'));

          dialogHeadingElement = dialogAlerts[j].querySelector('.deque-dialog-heading');
          dialogHeadingElement.setAttribute('id', dialogHeadingElement.getAttribute('id') + dialogDataId);

          //dialogDescriptionElement = dialogAlerts[j].querySelector('.deque-dialog-description');
          //dialogDescriptionElement.setAttribute('id', dialogDescriptionElement.getAttribute('id') + dialogDataId); 


          var dialogAlertDescription;
          var dialogAlertLabel;

          var configDialogAlert = {
            describedby: dialogAlertDescription,
            labelledby: dialogAlertLabel,
            isAlert: true
          };

          var triggerDialogAlert = document.getElementsByClassName('deque-dialog-alert-trigger deque-button');

          triggerDialogAlert[j].addEventListener('click', function (event) {
            event.preventDefault();
            dequeActiveDialogButton = triggerDialogAlert[i];
            var attributeDialogAlert = this.getAttribute('aria-controls');
            var showDialogAlert = createDialog(attributeDialogAlert, 'deque-dialog-alert');
            var dequeDialogWidgetElement = document.querySelectorAll('.deque-dialog-alert[data-id="' + event.currentTarget.getAttribute('data-id') + '"]')[0];
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-heading')) {
              configDialogAlert.describedby = dequeDialogWidgetElement.querySelector('.deque-dialog-heading').getAttribute('id');
            } else {
              configDialogAlert.describedby = '';
            }
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-description')) {
              configDialogAlert.labelledby = dequeDialogWidgetElement.querySelector('.deque-dialog-description').getAttribute('id');
            } else {
              configDialogAlert.labelledby = '';
            }

            showDialogAlert(this, configDialogAlert);
          });
        }

        //activate all dialog messages
        var dialogMessages = document.querySelectorAll('.deque-dialog-message');
        for (var k = 0; k < dialogMessages.length; k++) {
          dialogMessages[k].classList.add('deque-hidden');

          dialogDataId = '_' + dialogMessages[k].getAttribute('data-id');
          dialogMessages[k].setAttribute('id', dialogMessages[k].getAttribute('id') + dialogDataId);
          document.querySelector('button[data-id="' + dialogMessages[k].getAttribute('data-id') + '"]').setAttribute('aria-controls', dialogMessages[k].getAttribute('id'));

          dialogHeadingElement = dialogMessages[k].querySelector('.deque-dialog-heading');
          dialogHeadingElement.setAttribute('id', dialogHeadingElement.getAttribute('id') + dialogDataId);

          dialogDescriptionElement = dialogMessages[k].querySelector('.deque-dialog-description');
          dialogDescriptionElement.setAttribute('id', dialogDescriptionElement.getAttribute('id') + dialogDataId);

          var dialogMessageDescription;
          var dialogMessageLabel;

          var configDialogMessage = {
            describedby: dialogMessageDescription,
            labelledby: dialogMessageLabel,
            isAlert: false
          };

          var triggerDialogMessage = document.getElementsByClassName('deque-dialog-message-trigger deque-button');

          triggerDialogMessage[k].addEventListener('click', function (event) {
            event.preventDefault();
            dequeActiveDialogButton = triggerDialogMessage[i];
            var attributeDialogMessage = this.getAttribute('aria-controls');
            var showDialogMessage = createDialog(attributeDialogMessage, 'deque-dialog-message');
            var dequeDialogWidgetElement = document.querySelectorAll('.deque-dialog-message[data-id="' + event.currentTarget.getAttribute('data-id') + '"]')[0];
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-heading')) {
              configDialogMessage.describedby = dequeDialogWidgetElement.querySelector('.deque-dialog-heading').getAttribute('id');
            } else {
              configDialogMessage.describedby = '';
            }
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-description')) {
              configDialogMessage.labelledby = dequeDialogWidgetElement.querySelector('.deque-dialog-description').getAttribute('id');
            } else {
              configDialogMessage.labelledby = '';
            }
            showDialogMessage(this, configDialogMessage);
          });
        }

        //activate all dialog message alerts
        var dialogMessageAlerts = document.querySelectorAll('.deque-dialog-message-alert');
        for (var l = 0; l < dialogMessageAlerts.length; l++) {
          dialogMessageAlerts[l].classList.add('deque-hidden');

          dialogDataId = '_' + dialogMessageAlerts[l].getAttribute('data-id');
          dialogMessageAlerts[l].setAttribute('id', dialogMessageAlerts[l].getAttribute('id') + dialogDataId);
          document.querySelector('button[data-id="' + dialogMessageAlerts[l].getAttribute('data-id') + '"]').setAttribute('aria-controls', dialogMessageAlerts[l].getAttribute('id'));

          dialogHeadingElement = dialogMessageAlerts[l].querySelector('.deque-dialog-heading');
          dialogHeadingElement.setAttribute('id', dialogHeadingElement.getAttribute('id') + dialogDataId);

          dialogDescriptionElement = dialogMessageAlerts[l].querySelector('.deque-dialog-description');
          dialogDescriptionElement.setAttribute('id', dialogDescriptionElement.getAttribute('id') + dialogDataId);

          var dialogMessageAlertDescription;
          var dialogMessageAlertLabel;

          var configDialogMessageAlert = {
            describedby: dialogMessageAlertDescription,
            labelledby: dialogMessageAlertLabel,
            isAlert: true
          };

          var triggerDialogMessageAlert = document.getElementsByClassName('deque-dialog-message-alert-trigger deque-button');

          triggerDialogMessageAlert[l].addEventListener('click', function (event) {
            event.preventDefault();
            dequeActiveDialogButton = triggerDialogMessageAlert[i];
            var attributeDialogMessageAlert = this.getAttribute('aria-controls');
            var showDialogMessageAlert = createDialog(attributeDialogMessageAlert, 'deque-dialog-message-alert');

            var dequeDialogWidgetElement = document.querySelectorAll('.deque-dialog-message-alert[data-id="' + event.currentTarget.getAttribute('data-id') + '"]')[0];
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-heading')) {
              configDialogMessageAlert.describedby = dequeDialogWidgetElement.querySelector('.deque-dialog-heading').getAttribute('id');
            } else {
              configDialogMessageAlert.describedby = '';
            }
            if (dequeDialogWidgetElement.querySelector('.deque-dialog-description')) {
              configDialogMessageAlert.labelledby = dequeDialogWidgetElement.querySelector('.deque-dialog-description').getAttribute('id');
            } else {
              configDialogMessageAlert.labelledby = '';
            }
            showDialogMessageAlert(this, configDialogMessageAlert);
          });
        }

        if (!activateHander) {
          activateDequeDialogButtonClickHandlers();
          activateHander = true;
        }
      }

      window.onload = function () {
        activateAllDialogs();
      };

      

In the @focusUtils section:


      var focusableQuery = 'input:not([tabindex^="-"]), select:not([tabindex^="-"]), textarea:not([tabindex^="-"]), button:not([tabindex^="-"]), object:not([tabindex^="-"]), [href]:not([tabindex^="-"]), [tabindex]:not([tabindex^="-"]):not(.tabtrap)';

      function getFirstFocusableChild(element) {
        return element.querySelector(focusableQuery);
      }

      function getNextFocusableChild(element, current) {
        var all = (0, _selectionUtils.queryAll)(focusableQuery);
        var targetReturnIndex = all.indexOf(current) + 1;

        if (targetReturnIndex <= all.length - 1) {
          return all[targetReturnIndex];
        }

        return null;
      }

      function getLastFocusableChild(element) {
        var all = element.querySelectorAll(focusableQuery);
        return all[all.length - 1];
      }

      function initTabTrap(element) {
        function createTrap() {
          var trap = document.createElement('div');
          trap.classList.add('tabtrap');
          trap.setAttribute('tabindex', '0');

          return trap;
        }

        function applyTraps(element, firstTrap, lastTrap) {
          firstTrap.addEventListener('focus', function () {
            getLastFocusableChild(element).focus();
          });

          lastTrap.addEventListener('focus', function () {
            getFirstFocusableChild(element).focus();
          });

          element.insertBefore(firstTrap, element.firstChild);
          element.appendChild(lastTrap);
        }

        var firstTrap = createTrap();
        var lastTrap = createTrap();

        applyTraps(element, firstTrap, lastTrap);
      }
      

In the @dialog-contentArea section:

In the @dialog-buttonBar section:


      function getFirstButton(buttonBar) {
        return buttonBar.children[0] || null;
      }

      function getLastButton(buttonBar) {
        var buttons = buttonBar.children;
        return buttons[buttons.length - 1] || null;
      }

      function initializeButtonBar(buttonBar, config, hide) {
        formatButtons(config, hide).forEach(function (button, index, buttons) {
          buttonBar.appendChild(button.button);

          if (index < buttons.length - 1) {
            var space = document.createElement('span');
            space.innerHTML = '';
            buttonBar.appendChild(space);
          }
        });
      }

      function formatButtons(config, hide) {
        return config.map(function (buttonConfig) {
          var button;

          if (buttonConfig.markup) {
            var wrapper = document.createElement('div');
            wrapper.innerHTML = buttonConfig.markup;
            button = wrapper.querySelector('button');
            wrapper = null;
          } else {
            button = document.createElement('button');
            button.innerText = buttonConfig.label;
          }

          if (buttonConfig.classes) {
            buttonConfig.classes.forEach(function (c) {
              return button.classList.add(c);
            });
          }

          var handler = function handler() {
            if (buttonConfig.preClose) {
              buttonConfig.preClose();
            }

            hide();

            if (buttonConfig.postClose) {
              buttonConfig.postClose();
            }
          };

          button.addEventListener('click', handler);

          return {
            button: button,
            handler: handler
          };
        });
      }

      function createButtonBar(buttonBar) {
        //  var buttonBar = alert.querySelector('.deque-dialog-buttons');

        buttonBar.getFirstButton = getFirstButton.bind(null, buttonBar);
        buttonBar.getLastButton = getLastButton.bind(null, buttonBar);
        // buttonBar.clear = clearButtons.bind(null, buttonBar);
        buttonBar.initialize = initializeButtonBar.bind(null, buttonBar);

        return buttonBar;
      }
      

In the @dialog-lightboxScreen section:


      function clearScreen(screen) {
        screen.remove();
      }

      function showScreen(screen) {
        document.body.appendChild(screen);
      }

      function createScreen() {
        var screen = document.createElement('div');
        // screen.classList.add('deque-dialog-screen');
        screen.show = showScreen.bind(null, screen);
        screen.clear = clearScreen.bind(null, screen);

        return screen;
      }
      

In the @selectionUtils section:


      function queryAll(selector, context) {
        context = context || document;
        return (0, _collectionUtils.toArray)(context.querySelectorAll(selector));
      }
      

In the @collectionUtils section:


      function toArray(arraylike) {
        return Array.prototype.slice.call(arraylike);
      }
      

Note: No additional JavaScript initialization code is necessary for this pattern. All elements with class="deque-dialog-message" will be initialized automatically by the external JavaScript file.

CSS

Required: The complete CSS file (for all patterns in the library): deque-patterns.min.css

Key styles within the CSS file (other styles may also be necessary):


.deque-dialog-buttons button {
  cursor: pointer;
  color: #ffffff;
  background-color: #006cc1;
  font-size: 15px;
  max-width: 374px;
  min-width: 120px;
  display: inline-block;
  padding: 9px 12px 10px;
  border: solid 1px transparent;
  border-radius: 0;
  overflow: hidden;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: bottom;
  outline: none;
}
.deque-dialog-buttons button:hover {
  cursor: default;
}
.deque-dialog-trigger {
  cursor: pointer;
  background-color: #006cc1;
  font-size: 15px;
  max-width: 374px;
  min-width: 120px;
  display: inline-block;
  margin-top: 0;
  padding: 9px 12px 10px;
  border: solid 1px transparent;
  border-radius: 0;
  overflow: hidden;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: bottom;
  outline: none;
}
.deque-dialog-alert-trigger {
  cursor: pointer;
  background-color: #006cc1;
  font-size: 15px;
  max-width: 374px;
  min-width: 120px;
  display: inline-block;
  margin-top: 0;
  padding: 9px 12px 10px;
  border: solid 1px transparent;
  border-radius: 0;
  overflow: hidden;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: bottom;
  outline: none;
}
.deque-dialog-message-trigger {
  cursor: pointer;
  background-color: #006cc1;
  font-size: 15px;
  max-width: 374px;
  min-width: 120px;
  display: inline-block;
  margin-top: 0;
  padding: 9px 12px 10px;
  border: solid 1px transparent;
  border-radius: 0;
  overflow: hidden;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: bottom;
  outline: none;
}
.deque-dialog-message-alert-trigger {
  cursor: pointer;
  background-color: #006cc1;
  font-size: 15px;
  max-width: 374px;
  min-width: 120px;
  display: inline-block;
  margin-top: 0;
  padding: 9px 12px 10px;
  border: solid 1px transparent;
  border-radius: 0;
  overflow: hidden;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: bottom;
  outline: none;
}
.deque-dialog .deque-dialog-heading,
.deque-dialog-alert .deque-dialog-heading,
.deque-dialog-message .deque-dialog-heading,
.deque-dialog-message-alert .deque-dialog-heading {
  font-size: 20px;
  color: #2f2f2f;
  font-weight: 200;
  line-height: normal;
  padding: 0;
}
.deque-dialog.deque-dialog-noheading,
.deque-dialog-alert.deque-dialog-noheading,
.deque-dialog-message.deque-dialog-noheading,
.deque-dialog-message-alert.deque-dialog-noheading {
  text-align: center;
  font-size: 1.1em;
}
.deque-dialog-notify {
  background-color: #ff0000;
  color: #ffffff;
}
.deque-wrapper .feedback-holder {
  background-color: #fefee7;
  border: 2px solid #f5f573;
  padding: 20px 40px;
  display: block;
}
.deque-wrapper .feedback-holder:empty {
  display: none;
}
.deque-wrapper form.deque[data-feedback-type] .feedback-holder {
  outline: none;
}
.deque-wrapper .container .feedback-holder .info {
  border-color: #000066;
  background-color: #eeeeff;
  border: 1px solid;
  border-radius: 5px;
  margin: 5px auto;
  padding: 5px;
}
.deque-wrapper .container .feedback-holder .error {
  border-color: #660000;
  background-color: #fff5f5;
  border: 1px solid #ff9494;
  margin: 5px auto;
  padding: 5px;
}
.deque-wrapper .container .feedback-holder .success {
  border-color: #006600;
  background-color: #eeffee;
  border: 1px solid;
  border-radius: 5px;
  margin: 5px auto;
  padding: 5px;
}
.deque-dialog-buttons .deque-dialog-button-close {
  font-family: 'mwf-glyphs';
  font-size: 20px;
  width: 20px;
  height: 20px;
  right: 8px;
  top: 8px;
  position: absolute;
  background-color: transparent;
  display: block;
  overflow: visible;
  max-width: 20px;
  min-width: 20px;
  padding: 0;
}
.deque-dialog-buttons .deque-dialog-button-close span::before {
  content: '\E711';
  color: #006cc1;
  display: inline-block;
  font-size: 20px;
  width: 20px;
  height: 20px;
}
.deque-dialog-buttons .deque-dialog-button-close:focus {
  outline: 1px dashed #000000;
}
.deque-show-block .deque-dialog-screen-wrapper {
  display: block;
  content: '';
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.7);
  transition: opacity 200ms;
  opacity: 1;
}
.deque-hidden .deque-dialog-screen-wrapper {
  display: none;
}
.deque-show-block .deque-dialog-screen {
  display: block;
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: #ffffff;
  border: 1px solid #0078d7;
  margin: 0 auto;
  max-height: 760px;
  max-width: 546px;
  padding: 24px;
  z-index: 1000;
  outline: none;
  width: 80%;
  opacity: 1;
}
.deque-show-block .deque-dialog-screen .deque-dialog-buttons {
  margin-top: 20px;
}
.deque-hidden .deque-dialog-screen {
  display: none;
}

Fonts

Note: You will need to edit the src for font-family:'mwf-glyphs' in the external CSS file.

Implementation Instructions

Step 1: Add Dependencies

Add deque-patterns.min.css in the <head> of the document

<link rel="stylesheet" type="text/css" href="deque-patterns.min.css">

Add a script link to deque-patterns.min.js to the bottom of the page.

<script type="text/javascript" src="deque-patterns.min.js"></script>

Step 2: Add HTML

  • Wrap the HTML in a <div> or <span> container with class="deque-dialog-message", for styling purposes and to allow the javascript to initialize all the dialog boxes on the page.
    • Optional: Add a header to the dialog box in a <h1> container with class="deque-dialog-heading".
    • Optional: Add a description to the dialog box in a <p> container with class="deque-dialog-description".
    • The content of the dialog box needs to have the class="deque-dialog-content" and because this is a dialog message box the container should be a <div> with role="document".
      • In this example we included a <p> container with the content.
    • The small X in the upper right hand corner is automatically created with the dialog box, but if you would like to create more buttons create a <div> or <span> container with class="deque-dialog-buttons".
      • Each button is in a <button> container with class="deque-button".
  • Create the trigger to activate the dialog box within a <div> container.
    • In this example we used a <button> to trigger the dialog with id="deque-dialog-trigger", class="deque-dialog-trigger deque-button", and aria-controls="deque-dialog-message". The inner text is displayed on the button.