cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

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. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

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

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

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.

            
              <h1>MDN: Accessible Alternative to <code>title</code> Attribute</h1>

<p>
  This is an effort to remove reliance on the <code>title</code> attribute throughout the MDN web docs. Part of <a href="https://twitter.com/hashtag/HackOnMDN?src=hash">#HackOnMDN</a>.
</p>

<h2>Examples</h2>

<p>
  These are pulled from the the MDN site.
</p>

<h3>Using <code>title</code> Attribute</h3>

<p>
  <span class="seoSummary">The <strong><code>Map</code></strong> object holds key-value pairs.</span> Any value (both objects and <a href="/en-US/docs/Glossary/Primitive" class="glossaryLink" title="primitive values: A primitive (primitive value, primitive data type) is data that is not an object and has no methods. In JavaScript, there are 6 primitive data types: string, number, boolean, null, undefined, symbol (new in ECMAScript 2015).">primitive values</a>)
  may be used as either a key or a value.
</p>

<dl>
  <dt><code>iterable</code></dt>
  <dd>An <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" title="The JavaScript Array&nbsp;object is a global object that&nbsp;is used in the&nbsp;construction&nbsp;of&nbsp;arrays; which are high-level, list-like objects."><code>Array</code></a>    or other <a href="/en-US/docs/Web/JavaScript/Guide/iterable">iterable</a> object whose elements are key-value pairs (arrays with two elements, e.g. <code>[[ 1, 'one' ],[ 2, 'two' ]]</code>). Each key-value pair is added to the new <code>Map</code>;
    <code>null</code> values are treated as <code>undefined</code>.</dd>
</dl>

<h3>With <code>aria-describedby</code></h3>

<p>
  <span class="seoSummary">The <strong><code>Map</code></strong> object holds key-value pairs.</span> Any value (both objects and <a href="/en-US/docs/Glossary/Primitive" class="glossaryLink" aria-describedby="Foo1">primitive values<span id="Foo1" aria-hidden="true">primitive values: A primitive (primitive value, primitive data type) is data that is not an object and has no methods. In JavaScript, there are 6 primitive data types: string, number, boolean, null, undefined, symbol (new in ECMAScript 2015).</span></a>)
  may be used as either a key or a value.
</p>

<dl>
  <dt><code>iterable</code></dt>
  <dd>An <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" aria-describedby="Foo2"><code>Array</code><span id="Foo2" aria-hidden="true">The JavaScript Array&nbsp;object is a global object that&nbsp;is used in the&nbsp;construction&nbsp;of&nbsp;arrays; which are high-level, list-like objects.</span></a>    or other <a href="/en-US/docs/Web/JavaScript/Guide/iterable">iterable</a> object whose elements are key-value pairs (arrays with two elements, e.g. <code>[[ 1, 'one' ],[ 2, 'two' ]]</code>). Each key-value pair is added to the new <code>Map</code>;
    <code>null</code> values are treated as <code>undefined</code>.</dd>
</dl>

<h3>Using a Following <code>button</code></h3>

<p>
  <span class="seoSummary">The <strong><code>Map</code></strong> object holds key-value pairs.</span> Any value (both objects and <a href="/en-US/docs/Glossary/Primitive" class="glossaryLink" id="Lnk1">primitive values</a> <button type="button" id="Btn1" class="tip-button" aria-labelledby="More1 Lnk1" aria-expanded="false" aria-controls="Bar1" onclick="toggleToolTips(this.id);" data-aria-describedby="Bar1"><span>?</span><span id="More1"> More about</span></button><span id="Bar1" style="display:none;" tabindex="-1">primitive values: A primitive (primitive value, primitive data type) is data that is not an object and has no methods. In JavaScript, there are 6 primitive data types: string, number, boolean, null, undefined, symbol (new in ECMAScript 2015).</span>)
  may be used as either a key or a value.
</p>

<dl>
  <dt><code>iterable</code></dt>
  <dd>An <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" id="Lnk2"><code>Array</code></a> <button type="button" id="Btn2" class="tip-button" aria-labelledby="More2 Lnk2" aria-expanded="false" aria-controls="Bar2" onclick="toggleToolTips(this.id);" data-aria-describedby="Bar2"><span>?</span><span id="More2"> More about</span></button><span id="Bar2" style="display:none;" tabindex="-1">The JavaScript Array&nbsp;object is a global object that&nbsp;is used in the&nbsp;construction&nbsp;of&nbsp;arrays; which are high-level, list-like objects.</span>    or other <a href="/en-US/docs/Web/JavaScript/Guide/iterable">iterable</a> object whose elements are key-value pairs (arrays with two elements, e.g. <code>[[ 1, 'one' ],[ 2, 'two' ]]</code>). Each key-value pair is added to the new <code>Map</code>;
    <code>null</code> values are treated as <code>undefined</code>.</dd>
</dl>

<h2>What Is Happening</h2>

<ul>
  <li><code>title</code> attribute is removed,</li>
  <li>Write that content into the page as narrative text,</li>
  <li>Hide it from screen readers using <code>aria-hidden</code>,</li>
  <li>Visually hide it using CSS clipping techniques,</li>
  <li>Associate it with the link using <code>aria-describedby</code> (allowing it to be dismissed by screen reader users),</li>
  <li>Display it as a visible positioned box using CSS when the link has focus or is hovered,</li>
  <li>Dismiss it when pressing <kbd>Esc</kbd> to satisfy <a href="https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html">WCAG 1.4.13 Content on Hover or Focus (AA)</a>,</li>
  <li>Added underlines to the links to satisfy <a href="https://www.w3.org/WAI/WCAG21/Understanding/use-of-color.html">WCAG 1.4.1 Use of Color (A)</a>,</li>
  <li>Full-width tool-tips at smaller viewport width,</li>
  <li><strike>Responding to page width to prevent viewport overflow</strike>,</li>
  <li>Works in Internet Explorer 11.</li>
</ul>

<h3>Known Issues</h3>

<ul>
  <li>Positioning</li>
  <li>Jumping on reveal</li>
  <li>Focus management needs help</li>
</ul>

<h3>Supports:</h3>

<ul>
  <li>Keyboard users (beyond Internet Explorer and Edge),</li>
  <li>Windows High Contrast Mode users,</li>
  <li>Print users</li>
  <li><strike>Touch users</strike></li>
</ul>
            
          
!
            
              /* MDN styles */

body {
  line-height: 1.6;
  font-family: Verdana, arial, x-locale-body, sans-serif;
  letter-spacing: -0.00333rem;
  font-size: 15px;
  font-size: 1rem;
  color: #333;
}

:not(pre) > * > code,
:not(pre) > code {
  background-color: #bbb;
  background-color: rgba(220, 220, 220, 0.5);
  border-radius: 2px;
  box-decoration-break: clone;
  font-family: consolas, "Liberation Mono", courier, monospace;
  padding: 0 2px;
  word-wrap: break-word;
}

dt {
  font-style: normal;
  font-weight: 700;
}

a.glossaryLink:not(.new):active,
a.glossaryLink:not(.new):focus,
a.glossaryLink:not(.new):hover,
a.glossaryLink:not(.new):link,
a.glossaryLink:not(.new):visited {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dashed #aaa;
  cursor: help;
}

a,
a[name]:active,
a[name]:focus,
a[name]:hover {
  text-decoration: none;
}
a {
  text-decoration: none;
}

a:active,
a:focus,
a:hover {
  text-decoration: underline;
}

.cta-link,
a,
summary {
  color: #3f87a6;
}

h1,
h2,
h3 {
  /*     font-size: 32px;
    font-size: 2.13333rem; */
  /*     font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; */
  line-height: 1.2;
}

/* Custom for readability */

h2 {
  margin-top: 3em;
}

h3 {
  margin-top: 2.5em;
}

/* Fixing lack of underlines */

a,
a[name]:active,
a[name]:focus,
a[name]:hover {
  text-decoration: underline;
}

a.glossaryLink:not(.new):active,
a.glossaryLink:not(.new):focus,
a.glossaryLink:not(.new):hover,
a.glossaryLink:not(.new):link,
a.glossaryLink:not(.new):visited {
  border-bottom-color: #3f87a6;
}

/* Tool-tip replacement styles */

@media screen {
  a[aria-describedby] span[aria-hidden="true"] {
    position: absolute;
    top: auto;
    overflow: hidden;
    clip: rect(1px, 1px, 1px, 1px);
    width: 1px;
    height: 1px;
    white-space: nowrap;
  }
}

@media print {
  a[aria-describedby] span[aria-hidden="true"] {
    font-style: italic;
  }
}

a[aria-describedby] span[aria-hidden="true"]::before {
  content: " [";
}

a[aria-describedby] span[aria-hidden="true"]::after {
  content: "]";
}

/* Excludes IE11 */
a[aria-describedby]:focus span[aria-hidden="true"]:not([data-hide="true"]),
a[aria-describedby]:hover span[aria-hidden="true"]:not([data-hide="true"])
/* a[aria-describedby]:focus span[aria-hidden="true"],
a[aria-describedby]:hover span[aria-hidden="true"] */{
  display: block;
  z-index: 1;
  left: 0;
  clip: auto; /* IE11 does not support unset */
  width: auto;
  height: auto;
  padding: 0.5em 0.75em;
  border: 0.05em solid rgba(255, 255, 255, 1);
  border-radius: 0.2em;
  box-shadow: 0.15em 0.15em 0.5em rgba(0, 0, 0, 1);
  background-color: rgba(0, 0, 0, 0.85);
  color: rgba(255, 255, 255, 1);
  font-size: 80%;
  animation: TOOLTIP 0.1s ease-out 1;
  overflow: visible; /* IE11 does not support unset */
  white-space: normal; /* IE11 does not support unset */
  margin-top: 1.5em;
}

a[aria-describedby]:focus span[aria-hidden="true"]:not([data-hide="true"]),
a[aria-describedby]:hover span[aria-hidden="true"]:not([data-hide="true"]) {
  display: block;
  z-index: 1;
  left: 0;
  clip: auto; /* IE11 does not support unset */
  width: auto;
  height: auto;
  padding: 0.5em 0.75em;
  border: 0.05em solid rgba(255, 255, 255, 1);
  border-radius: 0.2em;
  box-shadow: 0.15em 0.15em 0.5em rgba(0, 0, 0, 1);
  background-color: rgba(0, 0, 0, 0.85);
  color: rgba(255, 255, 255, 1);
  font-size: 80%;
  animation: TOOLTIP 0.1s ease-out 1;
  overflow: visible; /* IE11 does not support unset */
  white-space: normal; /* IE11 does not support unset */
  margin-top: 1.5em;
}

a[aria-describedby]:focus span[aria-hidden="true"]::before,
a[aria-describedby]:hover span[aria-hidden="true"]::before,
a[aria-describedby]:focus span[aria-hidden="true"]::after,
a[aria-describedby]:hover span[aria-hidden="true"]::after {
  content: "";
}

@media screen and (min-width: 30em) {
  a[aria-describedby] {
    position: relative;
  }
  a[aria-describedby]:focus span[aria-hidden="true"],
  a[aria-describedby]:hover span[aria-hidden="true"] {
    max-width: 100vw;
    bottom: 1.5em;
    animation: TOOLTIP 0.1s ease-out 1;
    margin-top: unset;
  }
}

/* The animation */

@keyframes TOOLTIP {
  from {
    bottom: 0.5em;
    background-color: rgba(0, 0, 0, 0);
    border: 0.05em solid rgba(255, 255, 255, 0);
    color: rgba(255, 255, 255, 0);
    box-shadow: 0 0 0 rgba(0, 0, 0, 1);
  }
  to {
    bottom: 1.5em;
    background-color: rgba(0, 0, 0, 0.85);
    border: 0.05em solid rgba(255, 255, 255, 1);
    color: rgba(255, 255, 255, 1);
    box-shadow: 0.15em 0.15em 0.5em rgba(0, 0, 0, 1);
  }
}

/* Show it on paper */

/* @media print {
  span[role=img][aria-label]::after {
    content: " (" attr(aria-label) ") ";
  } */

/* Button approach styles */

.tip-button {
  /*   position: relative; */
  border: 0.1em solid #3f87a6;
  color: #3f87a6;
  background-color: transparent;
  font-family: inherit;
  font-size: 65%;
  border-radius: 50%;
  line-height: 1;
  text-align: center;
  padding: 0.2em 0;
  margin: 0;
  width: 1.5em;
  vertical-align: super;
}

.tip-button:hover,
.tip-button:focus {
  color: #fff;
  background-color: #3f87a6;
  outline: none;
}

.tip-button span:last-child {
  position: absolute;
  top: auto;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  width: 1px;
  height: 1px;
  white-space: nowrap;
}

.tip-button + span {
  display: block;
  position: absolute;
  z-index: 1;
  left: 0;
  width: auto;
  height: auto;
  padding: 0.5em 0.75em;
  border: 0.05em solid rgba(255, 255, 255, 1);
  border-radius: 0.2em;
  box-shadow: 0.15em 0.15em 0.5em rgba(0, 0, 0, 1);
  background-color: rgba(0, 0, 0, 0.85);
  color: rgba(255, 255, 255, 1);
  font-size: 80%;
  animation: TOOLTIP 0.1s ease-out 1;
  margin-top: 1.5em;
}

@media screen and (min-width: 30em) {
  .tip-button {
    /*     position: relative; */
  }
  .tip-button + span,
  .tip-button + span {
    max-width: 100vw;
    /*     bottom: 1.5em; */
    animation: TOOLTIP 0.1s ease-out 1;
    margin-top: unset;
  }
}

@media screen and (-ms-high-contrast: active) {
  .tip-button:hover,
  .tip-button:focus {
    outline: windowText dotted 0.1em;
  }
}

            
          
!
            
              function ClearToolTips() {
  // Get all the fake tool-tips
  var allTips = document.querySelectorAll(
    "a[aria-describedby]:focus span[aria-hidden='true'], a[aria-describedby]:hover span[aria-hidden='true']"
  );
  // Loop through all fake tool-tips and add an attribute
  for (var i = 0; i < allTips.length; i++) {
    allTips[i].setAttribute("data-hide", "true");
  }
}

function toggleToolTips(btnID) {
  try {
    // Get all the tool-tip buttons
    var allButtons = document.querySelectorAll(".tip-button");
    // Get all tool-tips
    var allToolTips = document.querySelectorAll(".tip-button + span");
    // Get all the button text
    var allButtonsToggleText = document.querySelectorAll(".tip-button span:first-child");
    var allButtonsInfoText = document.querySelectorAll(".tip-button span:last-child");
    if (btnID !== "") {
      // Get the button
      var toggle = document.querySelector("#" + btnID);
      // Find out what the button controls
      var toolTipIdent = toggle.getAttribute("aria-controls");
      // Get that thing it controls
      var toolTip = document.getElementById(toolTipIdent);
      // Toggle text and expanded state
      if (toggle.getAttribute("aria-expanded") === "false") {
        // Loop through all buttons and mark as closed
        for (var i = 0; i < allButtons.length; i++) {
          allButtons[i].setAttribute("aria-expanded", "false");
          allButtons[i].querySelector("span:first-child").innerHTML = "?";
          allButtons[i].querySelector("span:last-child").innerHTML =
            "More about";
        }
        // Now mark the chosen button as opened
        toggle.setAttribute("aria-expanded", "true");
        toggle.querySelector("span:first-child").innerHTML = "×";
        toggle.querySelector("span:last-child").innerHTML = "Close";
      } else {
        // Close chosen button; no need to loop through rest of nodes
        toggle.setAttribute("aria-expanded", "false");
        toggle.querySelector("span:first-child").innerHTML = "?";
        toggle.querySelector("span:last-child").innerHTML = "More about";
        toggle.focus();
      }
      // Expand or collapse
      if (toolTip.style.display === "none") {
        // Hide all submenus
        for (var i = 0; i < allToolTips.length; i++) {
          allToolTips[i].style.display = "none";
        }
        // Show chosen tool-tip
        toolTip.style.display = "block";
        toolTip.focus();
      } else {
        // Close chosen tool-tip; no need to loop through rest of nodes
        toolTip.style.display = "none";
      }
    }
    if (btnID !== "") {
    } else {
      // Hide all tool-tips
      for (var i = 0; i < allToolTips.length; i++) {
        allToolTips[i].style.display = "none";
      }
      // Loop through all buttons and mark as closed
      for (var i = 0; i < allButtons.length; i++) {
        allButtons[i].setAttribute("aria-expanded", "false");
        allButtons[i].querySelector("span:first-child").innerHTML = "?";
        allButtons[i].querySelector("span:last-child").innerHTML = "More about";
      }
    }
  } catch (e) {
    console.log("toggleToolTips(): " + e);
  }
}

document.onkeydown = function(evt) {
  evt = evt || window.event;
  var isEscape = false;
  if ("key" in evt) {
    isEscape = evt.key == "Escape" || evt.key == "Esc";
  } else {
    isEscape = evt.keyCode == 27;
  }
  if (isEscape) {
    // alert("Escape");
    ClearToolTips();
    toggleToolTips("");
  }
};

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console