Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Mutating the active element</title>
</head>
<body>
<article id="example-introduction">
  <h1>Mutating the active element</h1>
  <p>
    This document provides a simple way to test browsers&apos; behavior when the active element
    is mutated so that it isn&apos;t focusable anymore. The mutations include hiding and disabling
    disabling the element, as well as removing it from the DOM and removing the ability to
    receive focus by removing the <code>tabindex</code> attribute. Browser behavior can be
    observed for the elements <code>&lt;button&gt;</code>, <code>&lt;input&gt;</code> and
    <code>&lt;div&gt;</code>. At the end of the document the current active element is
    printed on screen for convenience.
  </p>
</article>
<div id="example-html">
  <main>
    <fieldset>
      <legend>Testing grounds</legend>
      <p><input id="alpha" value="alpha"></p>
      <div id="container" tabindex="-1">
        <p><input id="bravo" value="bravo"></p>
        <div class="trigger">
          <div><button type="button" id="trigger-button">click to mutate</button></div>
          <div hidden><input id="trigger-input" value="focus to mutate"></div>
          <div hidden><div id="trigger-div" role="button" tabindex="0">click to mutate</div></div>
        </div>
        <p><input id="charlie" value="charlie"></p>
      </div>
    </fieldset>
    <fieldset id="source">
      <legend>Element to mutate</legend>
      <p>Choose the type of element you want to observe the mutation on.</p>
      <ul>
        <li><label><input type="radio" name="source" value="button" id="source-button" checked> button element on click</label></li>
        <li><label><input type="radio" name="source" value="input" id="source-input"> input element on focus</label></li>
        <li><label><input type="radio" name="source" value="div" id="source-div"> div element on click</label></li>
      </ul>
      <p><label><input type="checkbox" name="delay" id="delay"> delay mutation for 50ms</label></p>
    </fieldset>
    <fieldset id="method">
      <legend>Method of mutation</legend>
      <p>Choose the way the element should lose the ability to receive focus.</p>
      <ul>
        <li><label><input type="radio" name="method" value="disabled" id="method-disabled" checked> disable element (not div)</label></li>
        <li><label><input type="radio" name="method" value="hidden" id="method-hidden"> hide element</label></li>
        <li><label><input type="radio" name="method" value="detached" id="method-detached"> detach element</label></li>
        <li><label><input type="radio" name="method" value="tabindex" id="method-tabindex" disabled> remove tabindex from element (only div)</label></li>
      </ul>
    </fieldset>
  </main>
  <div id="output">document.activeElement: <span id="active-element"></span></div>
</div>
</body>
</html>
 
main {
  display: flex;
  flex-direction: row;
}
main fieldset {
  flex: 1 1 auto;
}
main :focus {
  outline: 2px solid red;
}
main #container {
  border: 1px solid grey;
  padding: 0 10px;
}
main ul {
  margin: 0;
  padding: 0;
}
main li {
  display: block;
}
main .trigger {
  background: #eef;
  padding: 5px;
}
#output {
  margin-top: 10px;
  padding: 10px;
  background: #eee;
}
*[hidden] {
  display: none !important;
}
  
 
var triggers = {
  button: document.getElementById('trigger-button'),
  input: document.getElementById('trigger-input'),
  div: document.getElementById('trigger-div'),
};
var source = document.getElementById('source');
var sources = {
  button: document.getElementById('source-button'),
  input: document.getElementById('source-input'),
  div: document.getElementById('source-div'),
};
var _method = 'disabled';
var method = document.getElementById('method');
var methods = {
  disabled: document.getElementById('method-disabled'),
  hidden: document.getElementById('method-hidden'),
  detached: document.getElementById('method-detached'),
  tabindex: document.getElementById('method-tabindex'),
};
var mutations = {
  disabled: function(event) {
    console.log("disabling element");
    event.target.disabled = true;
    return function() {
      console.log("enabling element");
      event.target.disabled = false;
    };
  },
  hidden: function(event) {
    console.log("hiding element");
    event.target.setAttribute('hidden', '');
    return function() {
      console.log("showing element");
      event.target.removeAttribute('hidden');
    };
  },
  detached: function(event) {
    console.log("detaching element");
    var element = event.target;
    var container = element.parentNode;
    var dummy = document.createElement('div');
    container.insertBefore(dummy, element);
    container.removeChild(element);
    return function() {
    console.log("attaching element");
      container.insertBefore(element, dummy);
      container.removeChild(dummy);
    };
  },
  tabindex: function(event) {
    console.log("removing tabindex from element");
    event.target.removeAttribute('tabindex');
    return function() {
      console.log("restoring tabindex on element");
      event.target.setAttribute('tabindex', '0');
    };
  },
};
var mutate = mutations.disabled;
source.addEventListener('change', function() {
  Object.keys(triggers).forEach(function(key) {
    triggers[key].parentNode.hidden = !sources[key].checked;
  });
  methods.disabled.disabled = sources.div.checked;
  methods.tabindex.disabled = !sources.div.checked;
});
method.addEventListener('change', function() {
  var checked = this.querySelector(':checked');
  mutate = mutations[checked.value];
});
var delay = document.getElementById('delay');
function handleMutation(event) {
  var executeMutation = function() {
    var reset = mutate(event);
    reset && setTimeout(reset, 1000);
  };
  if (delay) {
    setTimeout(executeMutation, 50);
  } else {
    executeMutation();
  }
};
triggers.button.addEventListener('click', handleMutation, false);
triggers.input.addEventListener('focus', handleMutation, false);
triggers.div.addEventListener('click', handleMutation, false);
triggers.div.addEventListener('keyup', function(event) {
  if (event.keyCode !== 13 && event.keyCode !== 32) {
    return;
  }
  handleMutation(event);
}, false);
if (!window.requestAnimationFrame) {
  window.requestAnimationFrame = function(callback) {
    setTimeout(callback, 16);
  };
}
var activeElement = document.getElementById('active-element');
var previousActiveElement = document.getActiveElement;
function updateActiveElement() {
  requestAnimationFrame(updateActiveElement);
  if (previousActiveElement === document.activeElement) {
    return;
  }
  var ident = document.activeElement && (document.activeElement.id || document.activeElement.nodeName.toLowerCase()) || 'null';
  activeElement.textContent = ident;
  previousActiveElement = document.activeElement;
}
updateActiveElement();
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
rodneyrehmpro
0viewers