Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <main id="content">

  <h1><a href="http://websemantics.uk/articles/accessible-modal-dialog-popup-iframe/" target=_blank>ARIA accessible pop-up iframe modal (v2)</a></h1>

  <nav>
    <a href="https://codepen.io/2kool2/pen/KzXYmV" title="[new window]" target=_blank>Version 1</a>
    <a href="https://codepen.io/2kool2/pen/YqePqQ" title="[new window]" target=_blank>Version 2</a>
    <a href="https://codepen.io/2kool2/pen/dXazyK" title="[new window]" target=_blank>Version 3</a>
    <a href="https://codepen.io/2kool2/pen/LkaXay" title="[new window]" target=_blank>Version 4</a>
  </nav>

  <p>Vanilla JavaScript, no dependencies (but see <a href="https://codepen.io/2kool2/pen/LkaXay" title="[new window]" target=_blank>version 4</a>).</p>
  
  <p>This version uses the image as the activation button. Mainly due to issues encountered with Omniture hijacking link clicks on the Tesco servers.</p>

    <img class="img-map" src="https://websemantics.uk/portfolio/2016/finest-wine-bar/i/wine-bar-map-location.32.compressed.png" alt="Tesco finest* wine bar location" data-iframesrc="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d4175.8218601402605!2d-0.1390235133502716!3d51.51397674271494!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487604d357825039%3A0xf0c170d8fa918a9b!2s147+Wardour+St%2C+Soho%2C+London+W1F+8WD%2C+UK!5e0!3m2!1sen!2sin!4v1468326690641" data-type="interactive map">


  <p>
    <img class="img-map" src="https://websemantics.uk/portfolio/2016/finest-wine-bar/i/wine-bar-map-location.32.compressed.png" alt="Tesco finest* wine bar location" data-iframesrc="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d4175.8218601402605!2d-0.1390235133502716!3d51.51397674271494!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487604d357825039%3A0xf0c170d8fa918a9b!2s147+Wardour+St%2C+Soho%2C+London+W1F+8WD%2C+UK!5e0!3m2!1sen!2sin!4v1468326690641" data-type="interactive map">
  </p>

</main>



<!-- Footer codepen include -->
[[[https://codepen.io/2kool2/pen/mKeeGM]]]
              
            
!

CSS

              
                
/* Popup modal */

.modal-map {
  background-color: #fff;
  position: absolute;
  left: 10%;
  right: 10%;
  top: 5%;
  bottom: 5%;
  z-index: 10;
  border: 1px solid #3a3a3a;
  border-radius: .25rem;
  box-shadow: 0 .25rem .5rem rgba(0, 0, 0, .25);
  opacity: 0;
  transition: opacity 0.8s ease-out;
}

.modal-map[aria-hidden="false"] {
  position: fixed;
  opacity: 1;
}


/* Light box properties */

.lightbox {
  display: none;
  text-indent: -200em;
  background-color: rgba(0, 0, 0, 0.8);
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  /* places the modal overlay between the main page and the modal dialog*/
  z-index: 5;
  cursor: pointer;
}

.lightbox.ON {
  display: block;
}

.modal-title,
.modal-desc {
  position: absolute;
  top: 5px;
  left: -200rem;
  background-color: #fff;
  color: #000;
  text-shadow: 0 0 0 #fff;
  font-size: 1.5rem;
}

.modal-title:focus,
.modal-desc:focus {
  left: 5px;
}


/* The pop-ups close button, moved via CSS to the top right of the pop-up */

.btn-modalClose {
  position: absolute;
  top: -20px;
  right: -20px;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  background-color: #000;
  box-shadow: 0 .25rem .5rem rgba(0, 0, 0, .25);
  overflow: hidden;
}

.btn-modalClose:hover,
.btn-modalClose:active,
.btn-modalClose:focus {
  background-color: #c00;
}

.btn-modalClose span {
  position: absolute;
  top: 0;
  left: -200em;
  display: block;
}
.btn-modalClose svg {
  fill: #fff;
  vertical-align: middle;
  margin: 8px;
  pointer-events: none;
}
/* The pop-up content div will scroll if it has too much content */

.btn {
  border: 0 solid;
}
.img-map {
  display: block;
  width: 100%;
  margin: 2rem auto;
}
.img-map[role="button"] {
  cursor:pointer;
}
.img-map[role="button"]:hover,
.img-map[role="button"]:focus,
.img-map[role="button"]:active {
  box-shadow:0 0 0px 4px #fff;
  outline: 0 solid;
}

[role="dialog"][aria-hidden="true"] {
  display: none;
}

[role="dialog"][aria-hidden="false"] {
  display: block;
}


/* modal loading graphic - http://loading.io/ */

.modal-map {
  background-image: url("data:image/svg+xml;charset=utf8,<svg width='128' height='128' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='xMidYMid' class='uil-gears'><g transform='translate(-20,-20)'><path d='M79.9 52.6C80 51.8 80 50.9 80 50s0-1.8-0.1-2.6l-5.1-0.4c-0.3-2.4-0.9-4.6-1.8-6.7l4.2-2.9c-0.7-1.6-1.6-3.1-2.6-4.5L70 35c-1.4-1.9-3.1-3.5-4.9-4.9l2.2-4.6c-1.4-1-2.9-1.9-4.5-2.6L59.8 27c-2.1-0.9-4.4-1.5-6.7-1.8l-0.4-5.1C51.8 20 50.9 20 50 20s-1.8 0-2.6 0.1l-0.4 5.1c-2.4 0.3-4.6 0.9-6.7 1.8l-2.9-4.1c-1.6 0.7-3.1 1.6-4.5 2.6l2.1 4.6c-1.9 1.4-3.5 3.1-5 4.9l-4.5-2.1c-1 1.4-1.9 2.9-2.6 4.5l4.1 2.9c-0.9 2.1-1.5 4.4-1.8 6.8l-5 0.4C20 48.2 20 49.1 20 50s0 1.8 0.1 2.6l5 0.4c0.3 2.4 0.9 4.7 1.8 6.8l-4.1 2.9c0.7 1.6 1.6 3.1 2.6 4.5l4.5-2.1c1.4 1.9 3.1 3.5 5 4.9l-2.1 4.6c1.4 1 2.9 1.9 4.5 2.6l2.9-4.1c2.1 0.9 4.4 1.5 6.7 1.8l0.4 5.1C48.2 80 49.1 80 50 80s1.8 0 2.6-0.1l0.4-5.1c2.3-0.3 4.6-0.9 6.7-1.8l2.9 4.2c1.6-0.7 3.1-1.6 4.5-2.6L65 69.9c1.9-1.4 3.5-3 4.9-4.9l4.6 2.2c1-1.4 1.9-2.9 2.6-4.5L73 59.8c0.9-2.1 1.5-4.4 1.8-6.7L79.9 52.6zM50 65c-8.3 0-15-6.7-15-15 0-8.3 6.7-15 15-15s15 6.7 15 15C65 58.3 58.3 65 50 65z' fill='%239F9DB2'><animateTransform attributeName='transform' type='rotate' from='90 50 50' to='0 50 50' dur='1s' repeatCount='indefinite'/></path></g><g transform='translate(20,20) rotate(15 50 50)'><path d='M79.9 52.6C80 51.8 80 50.9 80 50s0-1.8-0.1-2.6l-5.1-0.4c-0.3-2.4-0.9-4.6-1.8-6.7l4.2-2.9c-0.7-1.6-1.6-3.1-2.6-4.5L70 35c-1.4-1.9-3.1-3.5-4.9-4.9l2.2-4.6c-1.4-1-2.9-1.9-4.5-2.6L59.8 27c-2.1-0.9-4.4-1.5-6.7-1.8l-0.4-5.1C51.8 20 50.9 20 50 20s-1.8 0-2.6 0.1l-0.4 5.1c-2.4 0.3-4.6 0.9-6.7 1.8l-2.9-4.1c-1.6 0.7-3.1 1.6-4.5 2.6l2.1 4.6c-1.9 1.4-3.5 3.1-5 4.9l-4.5-2.1c-1 1.4-1.9 2.9-2.6 4.5l4.1 2.9c-0.9 2.1-1.5 4.4-1.8 6.8l-5 0.4C20 48.2 20 49.1 20 50s0 1.8 0.1 2.6l5 0.4c0.3 2.4 0.9 4.7 1.8 6.8l-4.1 2.9c0.7 1.6 1.6 3.1 2.6 4.5l4.5-2.1c1.4 1.9 3.1 3.5 5 4.9l-2.1 4.6c1.4 1 2.9 1.9 4.5 2.6l2.9-4.1c2.1 0.9 4.4 1.5 6.7 1.8l0.4 5.1C48.2 80 49.1 80 50 80s1.8 0 2.6-0.1l0.4-5.1c2.3-0.3 4.6-0.9 6.7-1.8l2.9 4.2c1.6-0.7 3.1-1.6 4.5-2.6L65 69.9c1.9-1.4 3.5-3 4.9-4.9l4.6 2.2c1-1.4 1.9-2.9 2.6-4.5L73 59.8c0.9-2.1 1.5-4.4 1.8-6.7L79.9 52.6zM50 65c-8.3 0-15-6.7-15-15 0-8.3 6.7-15 15-15s15 6.7 15 15C65 58.3 58.3 65 50 65z' fill='%23C5D2E0'><animateTransform attributeName='transform' type='rotate' from='0 50 50' to='90 50 50' dur='1s' repeatCount='indefinite'/></path></g></svg>");
  background-repeat: no-repeat;
  background-position: center center;
}
              
            
!

JS

              
                (function() {

  "use strict";

  // Modal window iframe (map) version 2.0 09-04-2016

  // v2.0 - multiple versions, no button in html

  // Assumption:
  //    First object in modal is the modal title
  //    Last object is the modal close button
  // Therefore to keep tab control inside modal:
  //    listen for tab keypress on close button
  //    listen for shift-tab keypress on title
  //    Always listen for the ESC key.

  // To do:
  //    Window resize.
  //    Externalise hard coded attribute values.
  //    animate in out.

  var d = document;
  var content = d.getElementById("content");
  var imgBtns = d.querySelectorAll("[data-iframesrc]");
  var i;

  var _closeModal = function(e) {
    var count = e.target.count; // lightbox, modal (ESC key), close btn
    var modal = d.getElementById("modal_" + count);
    var lightbox = d.getElementById("lightbox_" + count);
    var imgBtn;
    if (modal) {
      modal.setAttribute("aria-hidden", "true");
      lightbox.className = lightbox.className.replace(" ON", "");
      content.setAttribute("aria-hidden", "false");
      imgBtn = d.getElementById(modal.returnId);
      // reset activation button press
      imgBtn.setAttribute("aria-pressed", "false");
      // move focus back to initialising button
      imgBtn.focus();
    }
  };

  var _createiframe = function(image, modalHeight) {
    var iframe = d.createElement("iframe");
    if (image) {
      iframe.src = image.getAttribute("data-iframesrc");
      iframe.width = image.offsetWidth;
      iframe.height = modalHeight;
      iframe.setAttribute("frameborder", 0);
      iframe.setAttribute("allowfullscreen", true);
    }
    return iframe;
  };

  var _modal_title_shiftTabKeyPressed = function(e) {
    // if tab key and shift
    if (e.which === 9 && e.shiftKey) {
      e.preventDefault();
      //focus on last object in modal (close btn)
      d.getElementById("modal_btn_close_" + e.target.count).focus();
    }
  };

  var _escKeyPressed = function(e) {
    // only if ESC pressed
    if (e.which === 27) {
      _closeModal(e);
    }
  };

  var _displayModal = function (modal, count) {
    var image = d.getElementById("modal_img_" + count);
    var modalHeight;

    if (image) {
      modalHeight = Math.min(modal.offsetHeight, image.offsetHeight);
      modal.style.maxHeight = modalHeight + "px";
      modal.replaceChild(_createiframe(image, modalHeight), image);
      // ESC key check
      modal.addEventListener("keydown", _escKeyPressed, false);
    }
  };

  var _openModal = function(e) {

    e.preventDefault();

    var count = e.target.count;
    var modal = d.getElementById("modal_" + count);
    var lightbox = d.getElementById("lightbox_" + count);
    var modal_title;

    if (modal && lightbox) {
      if (!lightbox.className.match(" ON")) {
        lightbox.className += " ON";
      }
      e.target.setAttribute("aria-pressed", "true");
      modal.setAttribute("aria-hidden", "false");
      _displayModal(modal, count);
      content.setAttribute("aria-hidden", "true");
      modal_title = d.getElementById("modal_title_" + count);
      if (modal_title) {
        modal_title.count = count;
        modal_title.addEventListener("keydown", _modal_title_shiftTabKeyPressed, false);
        // move focus to the modal h1
        modal_title.focus();
      }
    }
  };

  var _addLightbox = function(imgMapBtn) {
    var count = imgMapBtn.count;
    var lightboxDiv = d.createElement("div");
    lightboxDiv.id = "lightbox_" + count;
    lightboxDiv.className = "lightbox";
    lightboxDiv.count = count;
    lightboxDiv.returnId = imgMapBtn.id;
    // optional - should not be able to reach this via keyboard
    lightboxDiv.setAttribute("tabindex", "0");
    d.body.appendChild(lightboxDiv);
    // mouse / touch only
    lightboxDiv.addEventListener("click", _closeModal, false);
  };

  var _modal_closeBtn_tabKeyPressed = function(e) {
    // if tab key and not shift. ESC key handled separately by _escKeyPressed()
    if (e.which === 9 && !e.shiftKey) {
      e.preventDefault();
      //focus on first object in modal - or should it be the modal, requires testing
      d.getElementById("modal_title_" + e.target.count).focus();
      // console.log("modal close button keypress = " + e.which);
    }
  };

  var _getModalCloseBtnHTML = function (imgBtn) {
    var str;
    str = "<button id=modal_btn_close_" + imgBtn.count;
    str += " class=\"btn btn-modalClose\"><span>Close</span>";
    // SVG not checked in IE
    str += '<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"><title>Close modal</title><path d="M311.1,250.2L487.2,74c16.9-16.9,16.9-44.2,0-61.1C470.3-3.9,443-3.9,426.1,13L250,189.1L73.9,13C57-3.9,29.7-3.9,12.8,13s-16.8,44.2,0,61l176.1,176.1L12.8,426.3c-16.9,16.9-16.9,44.2,0,61.1c8.4,8.4,19.5,12.6,30.5,12.6s22.1-4.2,30.5-12.6L250,311.2l176.1,176.1c8.4,8.4,19.5,12.6,30.5,12.6s22.1-4.2,30.5-12.6c16.9-16.9,16.9-44.2,0-61.1L311.1,250.2z"></path></svg>';
    str += "</button>";
    return str;
  };

  var _addModalCloseBtn = function(imgBtn) {
    var modal = d.getElementById("modal_" + imgBtn.count);
    var closeBtn;
    if (modal) {
      modal.innerHTML += _getModalCloseBtnHTML(imgBtn);
      closeBtn = d.getElementById("modal_btn_close_" + imgBtn.count);
      if (closeBtn) {
        closeBtn.count = imgBtn.count;
        closeBtn.returnId = imgBtn.id;
        closeBtn.addEventListener("click", _closeModal, false);
        closeBtn.addEventListener("keydown", _modal_closeBtn_tabKeyPressed, false);
      }
    }
  };

  var _getModalHTML = function(imgBtn) {
    var str;
    str = "<h1 tabindex=0 id=modal_title_" + imgBtn.count + " class=modal-title>";
    str += imgBtn.alt.replace("Click for ", "");
    str += "</h1>";
    str += "<div tabindex=0 id=modal_desc_" + imgBtn.count + " class=modal-desc>";
    str += "Esc key to leave modal, tab &amp; shift-tab to move focus.";
    str += "</div>";
    str += "<img id=modal_img_" + imgBtn.count;
    str += " data-iframesrc=\"" + imgBtn.frameSrc + "\"";
    str += " class=img-map src=\"" + imgBtn.src + "\" alt=\"\">";
    return str;
  };

  var _addModalBlock = function(imgBtn) {
    var modal = d.createElement("section");
    modal.id = "modal_" + imgBtn.count;
    modal.returnId = imgBtn.id;
    modal.className = "modal-map";
    modal.setAttribute("aria-hidden", "true");
    modal.setAttribute("aria-labelledby", "modal_title_" + imgBtn.count);
    modal.setAttribute("aria-describedby", "modal_desc_" + imgBtn.count);
    modal.setAttribute("role", "dialog");
    modal.innerHTML = _getModalHTML(imgBtn);
    d.body.appendChild(modal);
  };

  var _imgBtn_enterSpacePressed = function(e) {
    // if enter or space key
    if (e.which === 13 || e.which === 32) {
      e.preventDefault();
      console.log("open " + e.target.count + " button pressed");
      _openModal(e);
    }
  };

  var _addButtonAttr = function (imgBtn) {
    imgBtn.id = imgBtn.id || "img_btn_" + imgBtn.count;
    imgBtn.setAttribute("role", "button");
    imgBtn.setAttribute("aria-pressed", "false");
    imgBtn.setAttribute("aria-controls", "modal_" + imgBtn.count);
    imgBtn.setAttribute("tabindex", "0");
    imgBtn.alt = "Click for " + imgBtn.alt + " ";
    imgBtn.alt += imgBtn.getAttribute("data-type");
    imgBtn.addEventListener("click", _openModal, false);
    imgBtn.addEventListener("keydown", _imgBtn_enterSpacePressed, false);
    console.log(imgBtn.count);
  };


  if (content && imgBtns) {
    i = imgBtns.length;
    while (i--) {
      imgBtns[i].frameSrc = imgBtns[i].getAttribute("data-iframesrc");
      imgBtns[i].count = i;
      _addButtonAttr(imgBtns[i]);
      _addModalBlock(imgBtns[i]);
      _addModalCloseBtn(imgBtns[i]);
      _addLightbox(imgBtns[i]);
    }
  }

}());
              
            
!
999px

Console