EU System

Expandables

When and how to use this component

If you need to present a lot of content on a page, it can be divided into sub-sections in a structured way.

When to use this component

  • when you have a large amount of information

Do not use this component

  • as a rule avoid hiding information as much as possible

Implementation

In order to automatically attach event listeners on your expandables, add the following script to your page (keep in mind that the selector is mandatory):

document.addEventListener('DOMContentLoaded', function() {
  ECL.initExpandables('#selector-of-my-expandable');
});

Change button label when the component is collapsed/expanded

You can attach data-label-expanded and data-label-collapsed attributes to your button. The button label will be updated dynamically according to these values. Check the first example for more information.

Resources

{#
  The following snippets are examples.
  The template should not be reused direclty.
#}

<!-- Button collapse -->

<div style="margin-top:1rem">
  {% include '@ecl/eu-component-button' with {
    'label': 'What is this all about?',
    'type_attribute': 'button',
    'extra_classes': 'ecl-expandable__button',
    'extra_attributes': [
      { 'name': 'aria-controls', 'value': 'example-expandable-1'},
      { 'name': 'aria-expanded', 'value': 'false'},
      { 'name': 'data-label-expanded', 'value': 'Hide me'},
      { 'name': 'data-label-collapsed', 'value': 'What is this all about?'},
      { 'name': 'id', 'value': 'example-expandable-button-1' },
    ]
  } %}
  <div
    aria-hidden="true"
    aria-labelledby="example-expandable-button-1"
    class="ecl-u-aria"
    id="example-expandable-1"
  >
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat...</p>
  </div>
</div>

<!-- Expandable link -->

<div style="margin-top:1rem">
  <a
    aria-controls="example-expandable-2"
    aria-expanded="false"
    class="ecl-link ecl-expandable__button"
    href="#"
    id="example-expandable-button-2"
  >
    Expandable link
  </a>
  <div
    aria-hidden="true"
    aria-labelledby="example-expandable-button-2"
    class="ecl-u-aria"
    id="example-expandable-2"
  >
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat...</p>
  </div>
</div>
{
  "_demo": {
    "scripts": "\n      document.addEventListener('DOMContentLoaded', function () {\n        ECL.initExpandables('#example-expandable-button-1, #example-expandable-button-2');\n      });\n    "
  }
}
<!-- Button collapse -->

<div style="margin-top:1rem">

  <button type="button" class="ecl-button ecl-button--default ecl-expandable__button" aria-controls="example-expandable-1" aria-expanded="false" data-label-expanded="Hide me" data-label-collapsed="What is this all about?" id="example-expandable-button-1">What is this all about?</button>
  <div aria-hidden="true" aria-labelledby="example-expandable-button-1" class="ecl-u-aria" id="example-expandable-1">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat...</p>
  </div>
</div>

<!-- Expandable link -->

<div style="margin-top:1rem">
  <a aria-controls="example-expandable-2" aria-expanded="false" class="ecl-link ecl-expandable__button" href="#" id="example-expandable-button-2">
    Expandable link
  </a>
  <div aria-hidden="true" aria-labelledby="example-expandable-button-2" class="ecl-u-aria" id="example-expandable-2">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat...</p>
  </div>
</div>
  • Content:
    /* eslint-disable no-param-reassign */
    
    export const toggleExpandable = (
      toggleElement,
      {
        context = document,
        forceClose = false,
        closeSiblings = false,
        siblingsSelector = '[aria-controls][aria-expanded]',
      } = {}
    ) => {
      if (!toggleElement) {
        return;
      }
    
      // Get target element
      const target = document.getElementById(
        toggleElement.getAttribute('aria-controls')
      );
    
      // Exit if no target found
      if (!target) {
        return;
      }
    
      // Get current status
      const isExpanded =
        forceClose === true ||
        toggleElement.getAttribute('aria-expanded') === 'true';
    
      // Toggle the expandable/collapsible
      toggleElement.setAttribute('aria-expanded', !isExpanded);
      target.setAttribute('aria-hidden', isExpanded);
    
      // Toggle label if possible
      if (!isExpanded && toggleElement.hasAttribute('data-label-expanded')) {
        toggleElement.innerHTML = toggleElement.getAttribute('data-label-expanded');
      } else if (isExpanded && toggleElement.hasAttribute('data-label-collapsed')) {
        toggleElement.innerHTML = toggleElement.getAttribute(
          'data-label-collapsed'
        );
      }
    
      // Close siblings if requested
      if (closeSiblings === true) {
        const siblingsArray = Array.prototype.slice
          .call(context.querySelectorAll(siblingsSelector))
          .filter(sibling => sibling !== toggleElement);
    
        siblingsArray.forEach(sibling => {
          toggleExpandable(sibling, {
            context,
            forceClose: true,
          });
        });
      }
    };
    
    // Helper method to automatically attach the event listener to all the expandables on page load
    export const initExpandables = (selector, context = document) => {
      // Exit if no selector was provided
      if (!selector) return;
    
      const nodesArray = Array.prototype.slice.call(
        context.querySelectorAll(selector)
      );
    
      nodesArray.forEach(node =>
        node.addEventListener('click', e => {
          toggleExpandable(node, { context });
          e.preventDefault();
        })
      );
    };
    
  • URL: /components/raw/eu-component-expandable/eu-component-expandable.js
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-expandable/eu-component-expandable.js
  • Size: 2 KB
  • Content:
    /**
     * ECL Expandable
     * @define expandable
     */
    
    // Import base and generic
    @import '@ecl/eu-base/eu-base';
    @import '@ecl/generic-component-expandable/generic-component-expandable';
    
    // Use generic mixin
    @include exports('eu-component-expandable') {
      @include ecl-expandable();
    }
    
  • URL: /components/raw/eu-component-expandable/eu-component-expandable.scss
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-expandable/eu-component-expandable.scss
  • Size: 281 Bytes
  • Handle: @ecl/eu-component-expandable
  • Tags: molecule
  • Preview:
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-expandable/eu-component-expandable.twig