Skip to main content

Your privacy settings

We use cookies to help you with journey planning and relevant disruptions, remember your login and show you content you might be interested in. If you’re happy with the use of cookies by West Midlands Combined Authority and our selected partners, click ‘Accept all cookies’. Or click ‘Manage cookies’ to learn more.

Manage Cookies
Beta

This is a new service - your feedback will help us to improve it.

Components

Details

About

What does it do?

  • Allows users to reveal more detailed information if they need it.
  • Allows users to scan the page more easily.

When to use it?

  • When you need to provide more detailed information.
  • When you need to hide extra information that only some users will need.
  • When you only need to provide 1 piece of extra information on the given subject.

When not to use it?

  • To hide information that is important to the majority of users
  • If you need to provide more than 1 piece of extra information related to a given subject. In this instance, use an Accordion.
  • To provide extra context inside a form. Users mistake it for a text link and worry they'll lose their data if they click.

How it works?

  • The details component expands into more detailed text when a user clicks on it.
  • Inside the <details> tag, include 1 <summary> and 1 <div> tag as direct children of <details>
  • Place your link text inside <summary> and the important information inside the <div>.

Using with IE11?

  • Make sure you include the polyfill in the recommended JavaScript below as the <details> and <summary> elements are not supported at IE11.

Closed


Detail heading

Lorem ipsum dolar sit...


HTML markup
<details class="wmnds-details">
  <summary class="wmnds-link">
    Detail heading
  </summary>
  <div class="wmnds-details__content">
    <p>Lorem ipsum dolar sit...</p>
  </div>
</details>

Nunjucks markup
{% from "wmnds/components/details/_details.njk" import wmndsDetails %}

{{
   wmndsDetails({
      headingText: "Detail heading",
      headingHTML: null,
      contentText: null,
      contentHTML: "<p><strong>Some random subtitle</strong></p>
      <p>Lorem ipsum dolor sit...</p>",
      isOpen: false
   })
}}

Nunjucks properties
NameTypeDescription
headingTextstringRequired. Text content for heading line. If headingHTML is supplied, this is ignored.
headingHTMLstringRequired. HTML content for heading line.
contentTextstringRequired. The text content of each section, which is hidden when the section is closed. If contentHTML is supplied, this is ignored.
contentHTMLstringRequired. The HTML content of each section, which is hidden when the section is closed.
isOpenbooleanIf true, details will be expanded upon initial load. Defaults to false.

Recommended javascript (browser compatible)
"use strict";

/*
Details Element Polyfill 2.4.0
Copyright © 2019 Javan Makhmali
 */
/* eslint-disable */

(function() {
  'use strict';

  var element = document.createElement('details');
  var elementIsNative = typeof HTMLDetailsElement != 'undefined' && element instanceof HTMLDetailsElement;
  var support = {
    open: 'open' in element || elementIsNative,
    toggle: 'ontoggle' in element
  };
  var styles = '\ndetails, summary {\n  display: block;\n}\ndetails:not([open]) > *:not(summary) {\n  display: none;\n}\nsummary::before {\n  content: "►";\n  padding-right: 0.3rem;\n  font-size: 0.6rem;\n  cursor: default;\n}\n[open] > summary::before {\n  content: "▼";\n}\n';
  var _ref = [],
    forEach = _ref.forEach,
    slice = _ref.slice;
  if (!support.open) {
    polyfillStyles();
    polyfillProperties();
    polyfillToggle();
    polyfillAccessibility();
  }
  if (support.open && !support.toggle) {
    polyfillToggleEvent();
  }

  function polyfillStyles() {
    document.head.insertAdjacentHTML('afterbegin', '<style>' + styles + '</style>');
  }

  function polyfillProperties() {
    var prototype = document.createElement('details').constructor.prototype;
    var setAttribute = prototype.setAttribute,
      removeAttribute = prototype.removeAttribute;
    var open = Object.getOwnPropertyDescriptor(prototype, 'open');
    Object.defineProperties(prototype, {
      open: {
        get: function get() {
          if (this.tagName == 'DETAILS') {
            return this.hasAttribute('open');
          } else {
            if (open && open.get) {
              return open.get.call(this);
            }
          }
        },
        set: function set(value) {
          if (this.tagName == 'DETAILS') {
            return value ? this.setAttribute('open', '') : this.removeAttribute('open');
          } else {
            if (open && open.set) {
              return open.set.call(this, value);
            }
          }
        }
      },
      setAttribute: {
        value: function value(name, _value) {
          var _this = this;
          var call = function call() {
            return setAttribute.call(_this, name, _value);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (!wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', true);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      },
      removeAttribute: {
        value: function value(name) {
          var _this2 = this;
          var call = function call() {
            return removeAttribute.call(_this2, name);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', false);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      }
    });
  }

  function polyfillToggle() {
    onTogglingTrigger(function(element) {
      element.hasAttribute('open') ? element.removeAttribute('open') : element.setAttribute('open', '');
    });
  }

  function polyfillToggleEvent() {
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          var target = mutation.target,
            attributeName = mutation.attributeName;
          if (target.tagName == 'DETAILS' && attributeName == 'open') {
            triggerToggle(target);
          }
        });
      }).observe(document.documentElement, {
        attributes: true,
        subtree: true
      });
    } else {
      onTogglingTrigger(function(element) {
        var wasOpen = element.getAttribute('open');
        setTimeout(function() {
          var isOpen = element.getAttribute('open');
          if (wasOpen != isOpen) {
            triggerToggle(element);
          }
        }, 1);
      });
    }
  }

  function polyfillAccessibility() {
    setAccessibilityAttributes(document);
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          forEach.call(mutation.addedNodes, setAccessibilityAttributes);
        });
      }).observe(document.documentElement, {
        subtree: true,
        childList: true
      });
    } else {
      document.addEventListener('DOMNodeInserted', function(event) {
        setAccessibilityAttributes(event.target);
      });
    }
  }

  function setAccessibilityAttributes(root) {
    findElementsWithTagName(root, 'SUMMARY').forEach(function(summary) {
      var details = findClosestElementWithTagName(summary, 'DETAILS');
      summary.setAttribute('aria-expanded', details.hasAttribute('open'));
      if (!summary.hasAttribute('tabindex')) summary.setAttribute('tabindex', '0');
      if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button');
    });
  }

  function eventIsSignificant(event) {
    return !(event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.target.isContentEditable);
  }

  function onTogglingTrigger(callback) {
    addEventListener('click', function(event) {
      if (eventIsSignificant(event)) {
        if (event.which <= 1) {
          var element = findClosestElementWithTagName(event.target, 'SUMMARY');
          if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
            callback(element.parentNode);
          }
        }
      }
    }, false);
    addEventListener('keydown', function(event) {
      if (eventIsSignificant(event)) {
        if (event.keyCode == 13 || event.keyCode == 32) {
          var element = findClosestElementWithTagName(event.target, 'SUMMARY');
          if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
            callback(element.parentNode);
            event.preventDefault();
          }
        }
      }
    }, false);
  }

  function triggerToggle(element) {
    var event = document.createEvent('Event');
    event.initEvent('toggle', false, false);
    element.dispatchEvent(event);
  }

  function findElementsWithTagName(root, tagName) {
    return (root.tagName == tagName ? [root] : []).concat(typeof root.getElementsByTagName == 'function' ? slice.call(root.getElementsByTagName(tagName)) : []);
  }

  function findClosestElementWithTagName(element, tagName) {
    if (typeof element.closest == 'function') {
      return element.closest(tagName);
    } else {
      while (element) {
        if (element.tagName == tagName) {
          return element;
        } else {
          element = element.parentNode;
        }
      }
    }
  }
})();

Recommended javascript (ES6)
/*
Details Element Polyfill 2.4.0
Copyright © 2019 Javan Makhmali
 */
/* eslint-disable */

(function() {
  'use strict';
  var element = document.createElement('details');
  var elementIsNative =
    typeof HTMLDetailsElement != 'undefined' && element instanceof HTMLDetailsElement;
  var support = {
    open: 'open' in element || elementIsNative,
    toggle: 'ontoggle' in element
  };
  var styles =
    '\ndetails, summary {\n  display: block;\n}\ndetails:not([open]) > *:not(summary) {\n  display: none;\n}\nsummary::before {\n  content: "►";\n  padding-right: 0.3rem;\n  font-size: 0.6rem;\n  cursor: default;\n}\n[open] > summary::before {\n  content: "▼";\n}\n';
  var _ref = [],
    forEach = _ref.forEach,
    slice = _ref.slice;
  if (!support.open) {
    polyfillStyles();
    polyfillProperties();
    polyfillToggle();
    polyfillAccessibility();
  }
  if (support.open && !support.toggle) {
    polyfillToggleEvent();
  }

  function polyfillStyles() {
    document.head.insertAdjacentHTML('afterbegin', '<style>' + styles + '</style>');
  }

  function polyfillProperties() {
    var prototype = document.createElement('details').constructor.prototype;
    var setAttribute = prototype.setAttribute,
      removeAttribute = prototype.removeAttribute;
    var open = Object.getOwnPropertyDescriptor(prototype, 'open');
    Object.defineProperties(prototype, {
      open: {
        get: function get() {
          if (this.tagName == 'DETAILS') {
            return this.hasAttribute('open');
          } else {
            if (open && open.get) {
              return open.get.call(this);
            }
          }
        },
        set: function set(value) {
          if (this.tagName == 'DETAILS') {
            return value ? this.setAttribute('open', '') : this.removeAttribute('open');
          } else {
            if (open && open.set) {
              return open.set.call(this, value);
            }
          }
        }
      },
      setAttribute: {
        value: function value(name, _value) {
          var _this = this;
          var call = function call() {
            return setAttribute.call(_this, name, _value);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (!wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', true);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      },
      removeAttribute: {
        value: function value(name) {
          var _this2 = this;
          var call = function call() {
            return removeAttribute.call(_this2, name);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', false);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      }
    });
  }

  function polyfillToggle() {
    onTogglingTrigger(function(element) {
      element.hasAttribute('open') ?
        element.removeAttribute('open') :
        element.setAttribute('open', '');
    });
  }

  function polyfillToggleEvent() {
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          var target = mutation.target,
            attributeName = mutation.attributeName;
          if (target.tagName == 'DETAILS' && attributeName == 'open') {
            triggerToggle(target);
          }
        });
      }).observe(document.documentElement, {
        attributes: true,
        subtree: true
      });
    } else {
      onTogglingTrigger(function(element) {
        var wasOpen = element.getAttribute('open');
        setTimeout(function() {
          var isOpen = element.getAttribute('open');
          if (wasOpen != isOpen) {
            triggerToggle(element);
          }
        }, 1);
      });
    }
  }

  function polyfillAccessibility() {
    setAccessibilityAttributes(document);
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          forEach.call(mutation.addedNodes, setAccessibilityAttributes);
        });
      }).observe(document.documentElement, {
        subtree: true,
        childList: true
      });
    } else {
      document.addEventListener('DOMNodeInserted', function(event) {
        setAccessibilityAttributes(event.target);
      });
    }
  }

  function setAccessibilityAttributes(root) {
    findElementsWithTagName(root, 'SUMMARY').forEach(function(summary) {
      var details = findClosestElementWithTagName(summary, 'DETAILS');
      summary.setAttribute('aria-expanded', details.hasAttribute('open'));
      if (!summary.hasAttribute('tabindex')) summary.setAttribute('tabindex', '0');
      if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button');
    });
  }

  function eventIsSignificant(event) {
    return !(
      event.defaultPrevented ||
      event.ctrlKey ||
      event.metaKey ||
      event.shiftKey ||
      event.target.isContentEditable
    );
  }

  function onTogglingTrigger(callback) {
    addEventListener(
      'click',
      function(event) {
        if (eventIsSignificant(event)) {
          if (event.which <= 1) {
            var element = findClosestElementWithTagName(event.target, 'SUMMARY');
            if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
              callback(element.parentNode);
            }
          }
        }
      },
      false
    );
    addEventListener(
      'keydown',
      function(event) {
        if (eventIsSignificant(event)) {
          if (event.keyCode == 13 || event.keyCode == 32) {
            var element = findClosestElementWithTagName(event.target, 'SUMMARY');
            if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
              callback(element.parentNode);
              event.preventDefault();
            }
          }
        }
      },
      false
    );
  }

  function triggerToggle(element) {
    var event = document.createEvent('Event');
    event.initEvent('toggle', false, false);
    element.dispatchEvent(event);
  }

  function findElementsWithTagName(root, tagName) {
    return (root.tagName == tagName ? [root] : []).concat(
      typeof root.getElementsByTagName == 'function' ?
      slice.call(root.getElementsByTagName(tagName)) :
      []
    );
  }

  function findClosestElementWithTagName(element, tagName) {
    if (typeof element.closest == 'function') {
      return element.closest(tagName);
    } else {
      while (element) {
        if (element.tagName == tagName) {
          return element;
        } else {
          element = element.parentNode;
        }
      }
    }
  }
})();

Expanded


Detail heading

Some random subtitle

Lorem ipsum dolor sit...


HTML markup
<details class="wmnds-details" open="true">
  <summary class="wmnds-link">
    Detail heading
  </summary>
  <div class="wmnds-details__content">
    <p><strong>Some random subtitle</strong></p>
    <p>Lorem ipsum dolor sit...</p>
  </div>
</details>

Nunjucks markup
{% from "wmnds/components/details/_details.njk" import wmndsDetails %}

{{
   wmndsDetails({
      headingText: "Detail heading",
      headingHTML: null,
      contentText: null,
      contentHTML: "<p><strong>Some random subtitle</strong></p>
      <p>Lorem ipsum dolor sit...</p>",
      isOpen: false
   })
}}

Nunjucks properties
NameTypeDescription
headingTextstringRequired. Text content for heading line. If headingHTML is supplied, this is ignored.
headingHTMLstringRequired. HTML content for heading line.
contentTextstringRequired. The text content of each section, which is hidden when the section is closed. If contentHTML is supplied, this is ignored.
contentHTMLstringRequired. The HTML content of each section, which is hidden when the section is closed.
isOpenbooleanIf true, details will be expanded upon initial load. Defaults to false.

Recommended javascript (browser compatible)
"use strict";

/*
Details Element Polyfill 2.4.0
Copyright © 2019 Javan Makhmali
 */
/* eslint-disable */

(function() {
  'use strict';

  var element = document.createElement('details');
  var elementIsNative = typeof HTMLDetailsElement != 'undefined' && element instanceof HTMLDetailsElement;
  var support = {
    open: 'open' in element || elementIsNative,
    toggle: 'ontoggle' in element
  };
  var styles = '\ndetails, summary {\n  display: block;\n}\ndetails:not([open]) > *:not(summary) {\n  display: none;\n}\nsummary::before {\n  content: "►";\n  padding-right: 0.3rem;\n  font-size: 0.6rem;\n  cursor: default;\n}\n[open] > summary::before {\n  content: "▼";\n}\n';
  var _ref = [],
    forEach = _ref.forEach,
    slice = _ref.slice;
  if (!support.open) {
    polyfillStyles();
    polyfillProperties();
    polyfillToggle();
    polyfillAccessibility();
  }
  if (support.open && !support.toggle) {
    polyfillToggleEvent();
  }

  function polyfillStyles() {
    document.head.insertAdjacentHTML('afterbegin', '<style>' + styles + '</style>');
  }

  function polyfillProperties() {
    var prototype = document.createElement('details').constructor.prototype;
    var setAttribute = prototype.setAttribute,
      removeAttribute = prototype.removeAttribute;
    var open = Object.getOwnPropertyDescriptor(prototype, 'open');
    Object.defineProperties(prototype, {
      open: {
        get: function get() {
          if (this.tagName == 'DETAILS') {
            return this.hasAttribute('open');
          } else {
            if (open && open.get) {
              return open.get.call(this);
            }
          }
        },
        set: function set(value) {
          if (this.tagName == 'DETAILS') {
            return value ? this.setAttribute('open', '') : this.removeAttribute('open');
          } else {
            if (open && open.set) {
              return open.set.call(this, value);
            }
          }
        }
      },
      setAttribute: {
        value: function value(name, _value) {
          var _this = this;
          var call = function call() {
            return setAttribute.call(_this, name, _value);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (!wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', true);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      },
      removeAttribute: {
        value: function value(name) {
          var _this2 = this;
          var call = function call() {
            return removeAttribute.call(_this2, name);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', false);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      }
    });
  }

  function polyfillToggle() {
    onTogglingTrigger(function(element) {
      element.hasAttribute('open') ? element.removeAttribute('open') : element.setAttribute('open', '');
    });
  }

  function polyfillToggleEvent() {
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          var target = mutation.target,
            attributeName = mutation.attributeName;
          if (target.tagName == 'DETAILS' && attributeName == 'open') {
            triggerToggle(target);
          }
        });
      }).observe(document.documentElement, {
        attributes: true,
        subtree: true
      });
    } else {
      onTogglingTrigger(function(element) {
        var wasOpen = element.getAttribute('open');
        setTimeout(function() {
          var isOpen = element.getAttribute('open');
          if (wasOpen != isOpen) {
            triggerToggle(element);
          }
        }, 1);
      });
    }
  }

  function polyfillAccessibility() {
    setAccessibilityAttributes(document);
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          forEach.call(mutation.addedNodes, setAccessibilityAttributes);
        });
      }).observe(document.documentElement, {
        subtree: true,
        childList: true
      });
    } else {
      document.addEventListener('DOMNodeInserted', function(event) {
        setAccessibilityAttributes(event.target);
      });
    }
  }

  function setAccessibilityAttributes(root) {
    findElementsWithTagName(root, 'SUMMARY').forEach(function(summary) {
      var details = findClosestElementWithTagName(summary, 'DETAILS');
      summary.setAttribute('aria-expanded', details.hasAttribute('open'));
      if (!summary.hasAttribute('tabindex')) summary.setAttribute('tabindex', '0');
      if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button');
    });
  }

  function eventIsSignificant(event) {
    return !(event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.target.isContentEditable);
  }

  function onTogglingTrigger(callback) {
    addEventListener('click', function(event) {
      if (eventIsSignificant(event)) {
        if (event.which <= 1) {
          var element = findClosestElementWithTagName(event.target, 'SUMMARY');
          if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
            callback(element.parentNode);
          }
        }
      }
    }, false);
    addEventListener('keydown', function(event) {
      if (eventIsSignificant(event)) {
        if (event.keyCode == 13 || event.keyCode == 32) {
          var element = findClosestElementWithTagName(event.target, 'SUMMARY');
          if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
            callback(element.parentNode);
            event.preventDefault();
          }
        }
      }
    }, false);
  }

  function triggerToggle(element) {
    var event = document.createEvent('Event');
    event.initEvent('toggle', false, false);
    element.dispatchEvent(event);
  }

  function findElementsWithTagName(root, tagName) {
    return (root.tagName == tagName ? [root] : []).concat(typeof root.getElementsByTagName == 'function' ? slice.call(root.getElementsByTagName(tagName)) : []);
  }

  function findClosestElementWithTagName(element, tagName) {
    if (typeof element.closest == 'function') {
      return element.closest(tagName);
    } else {
      while (element) {
        if (element.tagName == tagName) {
          return element;
        } else {
          element = element.parentNode;
        }
      }
    }
  }
})();

Recommended javascript (ES6)
/*
Details Element Polyfill 2.4.0
Copyright © 2019 Javan Makhmali
 */
/* eslint-disable */

(function() {
  'use strict';
  var element = document.createElement('details');
  var elementIsNative =
    typeof HTMLDetailsElement != 'undefined' && element instanceof HTMLDetailsElement;
  var support = {
    open: 'open' in element || elementIsNative,
    toggle: 'ontoggle' in element
  };
  var styles =
    '\ndetails, summary {\n  display: block;\n}\ndetails:not([open]) > *:not(summary) {\n  display: none;\n}\nsummary::before {\n  content: "►";\n  padding-right: 0.3rem;\n  font-size: 0.6rem;\n  cursor: default;\n}\n[open] > summary::before {\n  content: "▼";\n}\n';
  var _ref = [],
    forEach = _ref.forEach,
    slice = _ref.slice;
  if (!support.open) {
    polyfillStyles();
    polyfillProperties();
    polyfillToggle();
    polyfillAccessibility();
  }
  if (support.open && !support.toggle) {
    polyfillToggleEvent();
  }

  function polyfillStyles() {
    document.head.insertAdjacentHTML('afterbegin', '<style>' + styles + '</style>');
  }

  function polyfillProperties() {
    var prototype = document.createElement('details').constructor.prototype;
    var setAttribute = prototype.setAttribute,
      removeAttribute = prototype.removeAttribute;
    var open = Object.getOwnPropertyDescriptor(prototype, 'open');
    Object.defineProperties(prototype, {
      open: {
        get: function get() {
          if (this.tagName == 'DETAILS') {
            return this.hasAttribute('open');
          } else {
            if (open && open.get) {
              return open.get.call(this);
            }
          }
        },
        set: function set(value) {
          if (this.tagName == 'DETAILS') {
            return value ? this.setAttribute('open', '') : this.removeAttribute('open');
          } else {
            if (open && open.set) {
              return open.set.call(this, value);
            }
          }
        }
      },
      setAttribute: {
        value: function value(name, _value) {
          var _this = this;
          var call = function call() {
            return setAttribute.call(_this, name, _value);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (!wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', true);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      },
      removeAttribute: {
        value: function value(name) {
          var _this2 = this;
          var call = function call() {
            return removeAttribute.call(_this2, name);
          };
          if (name == 'open' && this.tagName == 'DETAILS') {
            var wasOpen = this.hasAttribute('open');
            var result = call();
            if (wasOpen) {
              var summary = this.querySelector('summary');
              if (summary) summary.setAttribute('aria-expanded', false);
              triggerToggle(this);
            }
            return result;
          }
          return call();
        }
      }
    });
  }

  function polyfillToggle() {
    onTogglingTrigger(function(element) {
      element.hasAttribute('open') ?
        element.removeAttribute('open') :
        element.setAttribute('open', '');
    });
  }

  function polyfillToggleEvent() {
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          var target = mutation.target,
            attributeName = mutation.attributeName;
          if (target.tagName == 'DETAILS' && attributeName == 'open') {
            triggerToggle(target);
          }
        });
      }).observe(document.documentElement, {
        attributes: true,
        subtree: true
      });
    } else {
      onTogglingTrigger(function(element) {
        var wasOpen = element.getAttribute('open');
        setTimeout(function() {
          var isOpen = element.getAttribute('open');
          if (wasOpen != isOpen) {
            triggerToggle(element);
          }
        }, 1);
      });
    }
  }

  function polyfillAccessibility() {
    setAccessibilityAttributes(document);
    if (window.MutationObserver) {
      new MutationObserver(function(mutations) {
        forEach.call(mutations, function(mutation) {
          forEach.call(mutation.addedNodes, setAccessibilityAttributes);
        });
      }).observe(document.documentElement, {
        subtree: true,
        childList: true
      });
    } else {
      document.addEventListener('DOMNodeInserted', function(event) {
        setAccessibilityAttributes(event.target);
      });
    }
  }

  function setAccessibilityAttributes(root) {
    findElementsWithTagName(root, 'SUMMARY').forEach(function(summary) {
      var details = findClosestElementWithTagName(summary, 'DETAILS');
      summary.setAttribute('aria-expanded', details.hasAttribute('open'));
      if (!summary.hasAttribute('tabindex')) summary.setAttribute('tabindex', '0');
      if (!summary.hasAttribute('role')) summary.setAttribute('role', 'button');
    });
  }

  function eventIsSignificant(event) {
    return !(
      event.defaultPrevented ||
      event.ctrlKey ||
      event.metaKey ||
      event.shiftKey ||
      event.target.isContentEditable
    );
  }

  function onTogglingTrigger(callback) {
    addEventListener(
      'click',
      function(event) {
        if (eventIsSignificant(event)) {
          if (event.which <= 1) {
            var element = findClosestElementWithTagName(event.target, 'SUMMARY');
            if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
              callback(element.parentNode);
            }
          }
        }
      },
      false
    );
    addEventListener(
      'keydown',
      function(event) {
        if (eventIsSignificant(event)) {
          if (event.keyCode == 13 || event.keyCode == 32) {
            var element = findClosestElementWithTagName(event.target, 'SUMMARY');
            if (element && element.parentNode && element.parentNode.tagName == 'DETAILS') {
              callback(element.parentNode);
              event.preventDefault();
            }
          }
        }
      },
      false
    );
  }

  function triggerToggle(element) {
    var event = document.createEvent('Event');
    event.initEvent('toggle', false, false);
    element.dispatchEvent(event);
  }

  function findElementsWithTagName(root, tagName) {
    return (root.tagName == tagName ? [root] : []).concat(
      typeof root.getElementsByTagName == 'function' ?
      slice.call(root.getElementsByTagName(tagName)) :
      []
    );
  }

  function findClosestElementWithTagName(element, tagName) {
    if (typeof element.closest == 'function') {
      return element.closest(tagName);
    } else {
      while (element) {
        if (element.tagName == tagName) {
          return element;
        } else {
          element = element.parentNode;
        }
      }
    }
  }
})();