JSFiddle - React, Tailwind, and code Playground

by ShaCP

HTML

<button onclick="openDialog('dialog1', this)">
  Add Delivery Address
</button>
<div role="dialog"
     id="dialog1"
     aria-labelledby="dialog1_label"
     aria-modal="true"
     class="hidden">
  <h2 id="dialog1_label" class="dialog_label">
    Add Delivery Address
  </h2>
  <div class="dialog_form">
    <div class="dialog_form_item">
      <label>
        <span class="label_text">
          Street:
        </span>
        <input type="text" class="wide_input">
      </label>
    </div>
    <div class="dialog_form_item">
      <label>
        <span class="label_text">
          City:
        </span>
        <input type="text" class="city_input">
      </label>
    </div>
    <div class="dialog_form_item">
      <label>
        <span class="label_text">
          State:
        </span>
        <input type="text" class="state_input">
      </label>
    </div>
    <div class="dialog_form_item">
      <label>
        <span class="label_text">
          Zip:
        </span>
        <input type="text" class="zip_input">
      </label>
    </div>
    <div class="dialog_form_item">
      <label for="special_instructions">
        <span class="label_text">
          Special instructions:
        </span>
      </label>
      <input id="special_instructions"
             type="text"
             aria-describedby="special_instructions_desc"
             class="wide_input">
      <div class="label_info" id="special_instructions_desc">
        For example, gate code or other information to help the driver find you
      </div>
    </div>
  </div>
  <div class="dialog_form_actions">
    <button onclick="openDialog('dialog2', this, 'dialog2_para1')">
      Verify Address
    </button>
    <button onclick="replaceDialog('dialog3', undefined, 'dialog3_close_btn')">
      Add
    </button>
    <button onclick="closeDialog(this)">
      Cancel
    </button>
  </div>
</div>
<!--  Second modal to open on top of the first modal  -->
<div id="dialog2"
     role="dialog"
    ...

CSS

.hidden {
  display: none;
}

[role="alertdialog"],
[role="dialog"] {
  box-sizing: border-box;
  padding: 15px;
  border: 1px solid #000;
  background-color: #fff;
  min-height: 100vh;
}

@media screen and (min-width: 640px) {
  [role="alertdialog"],
  [role="dialog"] {
    position: absolute;
    top: 2rem;
    left: 50vw;  /* move to the middle of the screen (assumes relative parent is the body/viewport) */
    transform: translateX(-50%);  /* move backwards 50% of this element's width */
    min-width: calc(640px - (15px * 2));  /* == breakpoint - left+right margin */
    min-height: auto;
    box-shadow: 0 19px 38px rgba(0, 0, 0, 0.12), 0 15px 12px rgba(0, 0, 0, 0.22);
  }
}

.dialog_label {
  text-align: center;
}

.dialog_form {
  margin: 15px;
}

.dialog_form .label_text {
  box-sizing: border-box;
  padding-right: 0.5em;
  display: inline-block;
  font-size: 16px;
  font-weight: bold;
  width: 30%;
  text-align: right;
}

.dialog_form .label_info {
  box-sizing: border-box;
  padding-right: 0.5em;
  font-size: 12px;
  width: 30%;
  text-align: right;
  display: inline-block;
}

.dialog_form_item {
  margin: 10px 0;
  font-size: 0;
}

.dialog_form_item .wide_input {
  box-sizing: border-box;
  max-width: 70%;
  width: 27em;
}

.dialog_form_item .city_input {
  box-sizing: border-box;
  max-width: 70%;
  width: 17em;
}

.dialog_form_item .state_input {
  box-sizing: border-box;
  max-width: 70%;
  width: 15em;
}

.dialog_form_item .zip_input {
  box-sizing: border-box;
  max-width: 70%;
  width: 9em;
}

.dialog_form_actions {
  text-align: right;
  padding: 0 20px 20px;
}

.dialog_close_button {
  float: right;
  position: absolute;
  top: 10px;
  left: 92%;
  height: 25px;
}

.dialog_close_button img {
  border: 0;
}

.dialog_desc {
  padding: 10px 20px;
}

/* native <dialog> element uses the ::backdrop pseudo-element */

/* dialog::backdrop, */
.dialog-backdrop {
  display: none;
  position: fixed;
  overflow-y: auto;
  top: 0;
  right: 0;
  bottom: 0;
 ...

JavaScript

/*
*   This content is licensed according to the W3C Software License at
*   https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*/

var aria = aria || {};

aria.Utils = aria.Utils || {};

(function () {
  /*
   * When util functions move focus around, set this true so the focus listener
   * can ignore the events.
   */
  aria.Utils.IgnoreUtilFocusChanges = false;

  aria.Utils.dialogOpenClass = 'has-dialog';

  /**
   * @desc Set focus on descendant nodes until the first focusable element is
   *       found.
   * @param element
   *          DOM node for which to find the first focusable descendant.
   * @returns
   *  true if a focusable element is found and focus is set.
   */
  aria.Utils.focusFirstDescendant = function (element) {
    for (var i = 0; i < element.childNodes.length; i++) {
      var child = element.childNodes[i];
      if (aria.Utils.attemptFocus(child) ||
          aria.Utils.focusFirstDescendant(child)) {
        return true;
      }
    }
    return false;
  }; // end focusFirstDescendant

  /**
   * @desc Find the last descendant node that is focusable.
   * @param element
   *          DOM node for which to find the last focusable descendant.
   * @returns
   *  true if a focusable element is found and focus is set.
   */
  aria.Utils.focusLastDescendant = function (element) {
    for (var i = element.childNodes.length - 1; i >= 0; i--) {
      var child = element.childNodes[i];
      if (aria.Utils.attemptFocus(child) ||
          aria.Utils.focusLastDescendant(child)) {
        return true;
      }
    }
    return false;
  }; // end focusLastDescendant

  /**
   * @desc Set Attempt to set focus on the current node.
   * @param element
   *          The node to attempt to focus on.
   * @returns
   *  true if element is focused.
   */
  aria.Utils.attemptFocus = function (element) {
    if (!aria.Utils.isFocusable(element)) {
      return false;
    }

    aria.Utils.IgnoreUtilFocusChanges = true;
    try {
     ...