Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs 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 its URL and the proper URL extension.

+ 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

Auto Save

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

              
                <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>
              
            
!

CSS

              
                /* 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;
  }
}

              
            
!

JS

              
                // Ref for later
// https://a11y.nicolas-hoffmann.net/simple-tooltip/


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

Console