City of Ghent Style Guide

Accordion

When to use this component

An accordion component is used to:

  • Show an overview of sections of multiple, related sections of content, that can be read independently from each other and which users typically are not interested to see all, but rather one or a few specific sections.
  • Make it possible for users to show or hide those section as needed.
  • Hide a simple piece or section of content that is advanced or that is only necessary for a minority of users (progressive disclosure principle).

When not to use this component

  • Do not use an accordion component to hide content that is essential to all users.
  • Do not use an accordion component when the amount of content in the items (when expanded) will make the page too long or too slow to load. Only use accordion components for simple content.

Alternatives to using an accordion component:

  • Reduce and simplify the content so that it can be placed as is on the page, without hiding it or the need for an accordion component.
  • Split the content accross multiple pages, especially if the amount of content is large (more than one text paragraph or if also other components than text paragraphs are needed to convey the message).
  • Keep the content as is on the page, separate the content by headings.
  • Use a table of contents component to let users navigate quickly to specific sections of content.

How it works

There are two types of accordions:

  • Single expandable item
  • Multiple expandable items
  • Expandable item with link

Adding the class ‘dropdown’ will add the following behaviour: when you click on an element that isn’t a dropdown, all dropdowns will be closed. This behaviour is used in the case of an application that doesn’t refresh when clicking a button or link.

Single expandable item

Accordions with one single expandable item are displayed with a chevron on the right-hand side.

  • When collapsed, the chevron points down, to indicate that it can be expanded.
  • When expanded, the chevron points up, to indicate that it can be collapsed.

By default, the single expandable item is collapsed.

The single expandable items has a label that tells what content is in the item. Do not start the label with a verb that describes the collapsing or expanding. This is not necessary because the item is already in an accordion. For example, if the item is a list of opening hours deze week, don’t use a label “Show opening hours this week” but use “Opening hours this week” instead.

Multiple expandable items

Accordions with multiple expandable items are displayed in a list of items with labels with a plus or a minus icon on the left-hand side of each item.

  • When an item is collapsed, the plus icon is shown, to indicate that it can be expanded.
  • When an item is expanded, the minus icon is shown, to indicate that it can be collapsed.

By default, all the expandable items are collapsed. Multiple items can be expanded at the same time.

The expandable items each have a label that tells what content is in the item. Do not start the label with a verb that describes the collapsing or expanding. This is not necessary because the item is already in an accordion. For example, if an item is about transportation by train, don’t use a label “Show transportation by train” but use “Transportation by train” instead.

Accordions that should be opened with a link, should have the .accordion--link class with buttons that have an .accordion--link--button class.

Make sure the ID is unique and the same in the aria-controls of the button.

Markup

  • Multiple expandable items must always be contained in an unordered- or description list.
  • The toggle must be of type button and preferably wrapped in an element with (implicit) role header.
  • The toggle button has both aria-expanded to indicate it’s current state and aria-controls to indicate which element it controls.

Javascript

Usage

Create a new accordion object by running:

new Accordion(element);

Where element contains a button with:

  • default class: accordion--button
  • aria-expanded (true or false)
  • aria-controls, the unique ID of the collapsible element

And a collapsible element with:

  • default class: accordion--content

By default, the accordion will initiate automatically and hide or show the content according to the aria-expanded attribute.
If the hash in the URL contains a matching ID, this element will also be expanded.

For instance:

<div class="accordion">
    <h3>
        <button aria-controls="accordion--content-ID"
                aria-expanded="false"
                class="accordion--button">
            single accordion
        </button>
    </h3>
    <div class="accordion--content" id="accordion--content-ID">
        ...
    </div>
</div>

Options

Option Type Default Description
expand function function(button, content) Function triggered after the expanded class is added, the ‘hidden’ attribute is removed from the content and aria-hidden is set to false.
collapse function function(button, content) Function triggered after the expanded class is removed and aria-hidden is set to true. By default, the ‘hidden’ attribute is set in the transitionEnd function
transitionEnd function function(event) Triggered for each transitionEnd event, use this to add the ‘hidden’ attribute after the content has been transitioned out of view.
resizeEvent function function(event, expandedContent) ExpandedContent is an array containing all expanded elements. Use this to trigger the ‘expand’ function on window.resize
init Boolean true Set to false if you want to manually initiate the accordion object (object.init())
buttonSelector String 'button.accordion--button' QuerySelector to identify the accordion trigger button
accordionExpandedClass String 'accordion--expanded' Determine which class is added to the expanded content.

Functions

Function Description
init() Manually initiate the accordion, this will expand or collapse all content according to the aria-expanded state
closeAll() Close all collapsible content in this accordion
openAll() Open all collapsible content in this accordion
<div class="accordion--link dropdown--link">
    <button aria-controls="accordion--link--single--content" type="button" class="accordion--button accordion--link--button" aria-expanded="false" >
        {{ buttonText }}
        {% include '@icon' with { "icon": "chevron-down" } %}
    </button>
    <div id="accordion--link--single--content" class="accordion--link--content" aria-hidden="true" hidden="hidden">
        {% include '@accordion--multiple' with {
            items: faqs
        } %}
    </div>
</div>
<div class="accordion--link dropdown--link">
    <button aria-controls="accordion--link--single--content" type="button" class="accordion--button accordion--link--button" aria-expanded="false">
        More info
        <i class="icon-chevron-down" aria-hidden="true"></i> </button>
    <div id="accordion--link--single--content" class="accordion--link--content" aria-hidden="true" hidden="hidden">
        <ul class="accordion">
            <li>
                <h3>
                    <button class="accordion--button" aria-expanded="false" aria-controls="accordion--multiple--content--1">
                        Croissant ice cream candy chocolate bar
                    </button>
                </h3>
                <div class="accordion--content" id="accordion--multiple--content--1">
                    <p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>
                </div>
            </li>
            <li>
                <h3>
                    <button class="accordion--button" aria-expanded="false" aria-controls="accordion--multiple--content--2">
                        Croissant ice cream candy chocolate bar
                    </button>
                </h3>
                <div class="accordion--content" id="accordion--multiple--content--2">
                    <p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>
                </div>
            </li>
            <li>
                <h3>
                    <button class="accordion--button" aria-expanded="false" aria-controls="accordion--multiple--content--3">
                        Croissant ice cream candy chocolate bar
                    </button>
                </h3>
                <div class="accordion--content" id="accordion--multiple--content--3">
                    <p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>
                </div>
            </li>
            <li>
                <h3>
                    <button class="accordion--button" aria-expanded="false" aria-controls="accordion--multiple--content--4">
                        Croissant ice cream candy chocolate bar
                    </button>
                </h3>
                <div class="accordion--content" id="accordion--multiple--content--4">
                    <p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>
                </div>
            </li>
            <li>
                <h3>
                    <button class="accordion--button" aria-expanded="false" aria-controls="accordion--multiple--content--5">
                        Croissant ice cream candy chocolate bar
                    </button>
                </h3>
                <div class="accordion--content" id="accordion--multiple--content--5">
                    <p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>
                </div>
            </li>
        </ul>
    </div>
</div>
{
  "buttonText": "More info",
  "faqs": [
    {
      "buttonText": "Croissant ice cream candy chocolate bar",
      "content": "<p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>"
    },
    {
      "buttonText": "Croissant ice cream candy chocolate bar",
      "content": "<p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>"
    },
    {
      "buttonText": "Croissant ice cream candy chocolate bar",
      "content": "<p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>"
    },
    {
      "buttonText": "Croissant ice cream candy chocolate bar",
      "content": "<p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>"
    },
    {
      "buttonText": "Croissant ice cream candy chocolate bar",
      "content": "<p>Sweet roll jelly-o lemon drops pudding bear claw. Powder cotton candy toffee chupa chups topping. Jelly cupcake cotton candy brownie dessert. Caramels cheesecake bonbon dragée chocolate cake. Cupcake brownie halvah halvah tiramisu tootsie roll cake jelly beans dragée. Lollipop marzipan apple pie bonbon soufflé cookie. Sesame snaps chocolate cheesecake muffin macaroon. Sweet roll cheesecake bonbon shortbread biscuit carrot cake. Sweet sesame snaps jelly croissant icing bonbon. Bear claw brownie wafer muffin lemon drops chupa chups dragée icing. Dragée lollipop jelly-o gingerbread cake. Pudding liquorice chocolate cupcake ice cream lollipop biscuit gingerbread.</p>"
    }
  ]
}
  • Content:
    .accordion {
      position: relative;
      z-index: 1;
    
      .accordion--button {
        @include extra-large-text;
        @include semi-bold-text;
        @include icon(chevron-down);
    
        position: relative;
        padding-right: 32px;
        color: inherit;
        line-height: 26px;
        text-align: left;
    
        &::before {
          position: absolute;
          right: 0;
          transition: transform .2s ease-out-in-out;
          font-size: 1.4rem;
          line-height: 1.2;
        }
    
        &[aria-expanded=true] {
          &::before {
            transform: scaleY(-1);
          }
        }
      }
    
      .accordion--content {
        max-height: 0;
        transition: max-height .75s ease-out;
        overflow: hidden;
    
        &.accordion--expanded {
          max-height: 9999px;
        }
    
        &:focus,
        &:focus-within {
          overflow: unset; // The overflow is needed for the accordion animation only
        }
    
        p {
          line-height: 1.75;
        }
      }
    
      .accordion {
        z-index: 2;
      }
    }
    
    ul.accordion,
    dl.accordion {
      &:not(.timeline) {
        & > li {
          @include theme('border-color', 'color-primary--lighten-4', 'accordion-border-color');
    
          border-bottom: 2px solid;
        }
      }
    
      li {
        h3 {
          margin: 20px 0;
        }
    
        &:first-child {
          h3 {
            margin-top: 0;
          }
        }
      }
    
      .accordion--button {
        display: flex;
        align-items: center;
        width: 100%;
        padding: 0;
        overflow: visible;
    
        &::before {
          @include theme('background-color', 'color-tertiary-pastel', 'button-secondary-background');
    
          position: relative;
          right: auto;
          left: 0;
          min-width: 36px;
          min-height: 36px;
          margin: 0 15px 0 0;
          padding: 2.5px 5px;
          transition: transform .2s ease-out-in-out;
          font-size: 1.2rem;
          text-align: left;
        }
    
        &[aria-expanded=true] {
          @include icon(minus);
    
          &::before {
            transform: none;
            line-height: 1.2;
          }
        }
    
        &[aria-expanded=false] {
          @include icon(plus);
    
          &::before {
            line-height: 1.2;
          }
        }
      }
    }
    
    ul.accordion {
      margin: 0;
    
      > li {
        list-style: none;
      }
    }
    
    dl.accordion {
      dd {
        padding: 0;
      }
    }
    
    .accordion--link {
      position: relative;
      z-index: 1;
    
      .accordion--link--button {
        @include remove-button;
        @include theme('color', 'color-tertiary', 'link-color');
        @include link-background('color-primary', 'color-primary', 'link-underline-color', 'link-hover-background');
        @include semi-bold-text;
    
        width: auto;
        margin-bottom: 20px;
        line-height: 120%;
        vertical-align: middle;
    
        &::before {
          display: none;
        }
    
        i {
          display: inline-block;
          margin-left: 5px;
          transform: rotate(0deg);
          transform-origin: center center;
          transition: .3s;
          vertical-align: middle;
        }
    
        &[aria-expanded=true] {
          i {
            transform: rotate(180deg);
          }
        }
      }
    
      .accordion--link--content {
        max-height: 0;
        transition: max-height .75s ease-out;
        overflow: hidden;
    
        &.accordion--expanded {
          max-height: 9999px;
        }
    
        &:focus,
        &:focus-within {
          overflow: unset; // The overflow is needed for the accordion animation only
        }
    
        p {
          line-height: 1.75;
        }
      }
    
      .accordion {
        z-index: 2;
      }
    }
    
  • URL: /components/raw/accordion/_accordion.scss
  • Filesystem Path: components/31-molecules/accordion/_accordion.scss
  • Size: 3.2 KB
  • Content:
    'use strict';
    
    (function () {
      if (!Accordion) { // eslint-disable-line no-undef
        return;
      }
    
      const selected = document.querySelectorAll('.accordion');
      for (let i = selected.length; i--;) {
        new Accordion(selected[i]); // eslint-disable-line no-undef
      }
    
      const selectedMore = document.querySelectorAll('.accordion--link');
      for (let x = selectedMore.length; x--;) {
        new Accordion(selectedMore[x]); // eslint-disable-line no-undef
      }
    })();
    
  • URL: /components/raw/accordion/accordion.bindings.js
  • Filesystem Path: components/31-molecules/accordion/accordion.bindings.js
  • Size: 460 Bytes
  • Content:
    'use strict';
    
    (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
        define(factory);
      }
      else {
        if (typeof exports === 'object') {
          module.exports = factory();
        }
        else {
          root.Accordion = factory();
        }
      }
    }(this || window, function () {
    
      return function (elem, options) {
    
        let expandedContent = [];
    
        /**
         * Override default options with options param.
         */
        options = (() => {
          const defaults = {
            expand: (button, content) => {
              // content.style.maxHeight = `${content.scrollHeight}px`;
            },
            collapse: (button, content) => {
              // content.style.maxHeight = 0;
            },
            transitionEnd: (e) => {
              if (e.propertyName !== 'max-height') {
                return;
              }
              if (!e.currentTarget.classList.contains('accordion--expanded')) {
                e.currentTarget.setAttribute('hidden', 'hidden');
              }
            },
            resizeEvent: (e, expandedContent) => {
              for (let i = expandedContent.length; i--;) {
                options.expand(null, expandedContent[i]);
              }
            },
            init: true,
            buttonSelector: 'button.accordion--button',
            linkSelector: 'button.accordion--link--button',
            accordionExpandedClass: 'accordion--expanded'
          };
    
          const keys = Object.keys(defaults);
          options = options || {};
    
          for (let i = keys.length; i--;) {
            options[keys[i]] = options[keys[i]] || defaults[keys[i]];
          }
    
          return options;
        })();
    
        // Check if there's a More info link
        let buttons;
        if (elem.querySelectorAll(options.linkSelector).length === 0) {
          buttons = elem.querySelectorAll(options.buttonSelector);
        }
        else {
          buttons = elem.querySelectorAll(options.linkSelector);
        }
    
        /**
         * Toggle aria-expanded attributes and trigger visibility Change function.
         *
         * @param {event} e The triggered event.
         */
        const toggle = (e) => {
          e.preventDefault();
          const button = e.currentTarget;
          button.setAttribute('aria-expanded', button.getAttribute('aria-expanded') === 'true' ? 'false' : 'true');
          setVisibility(button);
        };
    
        /**
         * Handle keyboard input: arrows, home & end.
         *
         * @param {event} e The triggered event.
         */
        const keyDown = (e) => {
          const keyCode = e.keyCode || e.which;
          let current = (() => {
            for (let i = buttons.length; i--;) {
              if (buttons[i] === e.currentTarget) {
                return i;
              }
            }
          })();
          switch (keyCode) {
            case 40: // arrow down
              e.preventDefault();
              if (current === buttons.length - 1) {
                current = -1;
              }
              buttons[current + 1].focus();
              break;
            case 38: // arrow up
              e.preventDefault();
              if (current === 0) {
                current = buttons.length;
              }
              buttons[current - 1].focus();
              break;
            case 36: // home
              e.preventDefault();
              buttons[0].focus();
              break;
            case 35: // end
              e.preventDefault();
              buttons[buttons.length - 1].focus();
              break;
          }
        };
    
        /**
         * Add events to buttons.
         * Listen for animationEnd on accordionContent.
         */
        const addEvents = () => {
          const onResize = (e) => {
            options.resizeEvent(e, expandedContent);
          };
    
          for (let i = buttons.length; i--;) {
            const button = buttons[i];
            button.addEventListener('click', toggle);
            button.addEventListener('keydown', keyDown);
    
            const accordionContent = elem.querySelector(`#${button.getAttribute('aria-controls')}`);
            const accordionContentImage = elem.querySelector(`#${button.getAttribute('data-controls-img')}`);
            accordionContent.addEventListener('transitionend', options.transitionEnd);
    
            if (accordionContentImage) {
              accordionContentImage.addEventListener('transitionend', options.transitionEnd);
            }
    
            if (options.resizeEvent) {
              window.addEventListener('resize', onResize);
            }
          }
    
          window.addEventListener('hashchange', hashEvent);
        };
    
        /**
         * Hide or show the accordion content.
         *
         * @param {Object} button  The accordion button.
         * @param {boolean|false} isInitial  True if this is the first run
         *   triggered by init().
         */
        const setVisibility = (button, isInitial) => {
    
          const accordionContent = elem.querySelector(`#${button.getAttribute('aria-controls')}`);
          const accordionContentImage = elem.querySelector(`#${button.getAttribute('data-controls-img')}`);
    
          if (!accordionContent) {
            return;
          }
    
          if (button.getAttribute('aria-expanded') === 'true') {
            accordionContent.classList.add(options.accordionExpandedClass);
            accordionContent.setAttribute('aria-hidden', 'false');
            accordionContent.removeAttribute('hidden');
            expandedContent.push(accordionContent);
            if (accordionContentImage) {
              accordionContentImage.classList.add(options.accordionExpandedClass);
              accordionContentImage.setAttribute('aria-hidden', 'false');
              accordionContentImage.removeAttribute('hidden');
              expandedContent.push(accordionContentImage);
              options.expand(button, accordionContentImage);
            }
            options.expand(button, accordionContent);
          }
          else {
            accordionContent.classList.remove(options.accordionExpandedClass);
            accordionContent.setAttribute('aria-hidden', 'true');
            if (isInitial) {
              accordionContent.setAttribute('hidden', 'hidden');
            }
            if (accordionContentImage) {
              accordionContentImage.classList.remove(options.accordionExpandedClass);
              accordionContentImage.setAttribute('aria-hidden', 'true');
              if (isInitial) {
                accordionContentImage.setAttribute('hidden', 'hidden');
              }
              expandedContent.filter(content => content !== accordionContentImage);
              options.collapse(button, accordionContentImage);
            }
            expandedContent.filter(content => content !== accordionContent);
            options.collapse(button, accordionContent);
          }
        };
    
        /**
         * Hide dropdowns when clicking outside the element.
         *
         * @param {Object} event  The js event.
         */
        window.onclick = function (event) {
          if (!event.target.matches('.dropdown button, .opening-hours *, .dropdown--link button')) {
            var dropdowns = elem.getElementsByClassName('dropdown');
            /* eslint-disable */
            for (var i = 0; i < dropdowns.length; i++) {
              var button = dropdowns[i].querySelector('button');
    
              if (button.getAttribute('aria-expanded') === 'false') {
                return;
              }
    
              const accordionContent = dropdowns[i].querySelector(`#${button.getAttribute('aria-controls')}`);
              const accordionContentImage = dropdowns[i].querySelector(`#${button.getAttribute('data-controls-img')}`);
              if (!accordionContent) {
                return;
              }
    
              accordionContent.classList.remove(options.accordionExpandedClass);
              accordionContent.setAttribute('aria-hidden', 'true');
              accordionContent.setAttribute('hidden', 'hidden');
              expandedContent.filter(content => content !== accordionContent);
              options.collapse(button, accordionContent);
              button.setAttribute('aria-expanded', 'false');
    
              if (accordionContentImage) {
                accordionContentImage.classList.remove(options.accordionExpandedClass);
                accordionContentImage.setAttribute('aria-hidden', 'true');
                accordionContentImage.setAttribute('hidden', 'hidden');
                expandedContent.filter(content => content !== accordionContentImage);
                options.collapse(button, accordionContentImage);
              }
            }
    
            var dropdownlinks = elem.getElementsByClassName('dropdown--link');
            for (var i = 0; i < dropdownlinks.length; i++) {
              var link = dropdowns[i].querySelector('button.accordion--link--button');
    
              if (link.getAttribute('aria-expanded') === 'false') {
                return;
              }
    
              const accordionContent = dropdowns[i].querySelector(`#${link.getAttribute('aria-controls')}`);
              const accordionContentImage = dropdowns[i].querySelector(`#${link.getAttribute('data-controls-img')}`);
              if (!accordionContent) {
                return;
              }
    
              accordionContent.classList.remove(options.accordionExpandedClass);
              accordionContent.setAttribute('aria-hidden', 'true');
              accordionContent.setAttribute('hidden', 'hidden');
              expandedContent.filter(content => content !== accordionContent);
              options.collapse(link, accordionContent);
              link.setAttribute('aria-expanded', 'false');
    
              if (accordionContentImage) {
                accordionContentImage.classList.remove(options.accordionExpandedClass);
                accordionContentImage.setAttribute('aria-hidden', 'true');
                accordionContentImage.setAttribute('hidden', 'hidden');
                expandedContent.filter(content => content !== accordionContentImage);
                options.collapse(link, accordionContentImage);
              }
            }
            /* eslint-enable */
          }
        };
    
        /**
         * Set all attributes and toggle visibility accordingly.
         */
        const setInitial = () => {
          for (let i = buttons.length; i--;) {
            setVisibility(buttons[i], true);
          }
        };
    
        const close = (button) => {
          button.setAttribute('aria-expanded', 'false');
          setVisibility(button);
        };
    
        /**
         * Closes all accordion items.
         */
        const closeAll = () => {
          for (let i = buttons.length; i--;) {
            close(buttons[i]);
          }
        };
    
        const open = (button) => {
          button.setAttribute('aria-expanded', 'true');
          setVisibility(button);
        };
    
        /**
         * Opens all accordion items.
         */
        const openAll = () => {
          for (let i = buttons.length; i--;) {
            open(buttons[i]);
          }
        };
    
        /**
         * Open the accordion-content related to the location hash.
         */
        const hashEvent = () => {
          let hash = window.location.hash.replace('#', '');
          if (!hash) {
            return;
          }
          try {
            const trigger = elem.querySelector(`[aria-controls=${hash}]`);
            if (trigger) {
              open(trigger);
              trigger.focus();
            }
          }
          catch (e) { }
        };
    
        /**
         * Enable accordion functionality.
         */
        const init = () => {
          setInitial();
          addEvents();
          hashEvent();
        };
    
        if (options.init !== false) {
          init();
        }
    
        return {init, closeAll, openAll};
      };
    }));
    
  • URL: /components/raw/accordion/accordion.functions.js
  • Filesystem Path: components/31-molecules/accordion/accordion.functions.js
  • Size: 10.9 KB