Accordions
Why 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.
The accordion component is a list of headers that can be clicked to hide or reveal additional content. It is also possible to add an icon to the headers.
When to use this component
- when you have a large amount of information
- on FAQ pages
Do not use this component
- as a rule avoid hiding information as much as possible
Resources
WAI-ARIA Authoring Practices
Latest Version (14 December 2016)
Current draft (as seen on 21 June 2017)
Existing libraries
{#
Parameters:
- "panels" (array) (default: ""): format [
{
"id" (string) (default: '')
"isExpanded" (boolean) (default: false)
"heading": {
"level" (string) (default: '')
"title" (string) (default: '')
"icon" (string) (default: '')
},
"body" (string) (default: '')
},
...
]
- "extra_classes" (string) (default: '')
- "extra_attributes" (array) (default: []): format: [
{
'name': 'name_of_the_attribute',
'value': 'value_of_the_attribute'
},
...
]
#}
{% include '@ecl/generic-component-accordion' %}
{
"_demo": {
"scripts": "document.addEventListener('DOMContentLoaded', function () {\n ECL.accordions();\n });"
},
"panels": [
{
"id": "pan1",
"heading": {
"title": "Jobs, Growth, Investment and Competitiveness with an additional quite long string",
"icon": "growth",
"level": 2
},
"body": "<p class=\"ecl-paragraph\">Bullfights. Bull hockey. Do you like this? The bull is stabbed, prodded, beaten. The bull is wounded. The bull is tired before the matador ever steps into the ring. Now, is that victory? Of course it is. Wanna know the secret to winning? Creative sportsmanship. In other words, one has to rig the game.</p>"
},
{
"id": "pan2",
"heading": {
"title": "Energy Union",
"icon": "energy",
"level": 2
},
"body": "<p class=\"ecl-paragraph\">Bullfights. Bull hockey. Do you like this? The bull is stabbed, prodded, beaten. The bull is wounded. The bull is tired before the matador ever steps into the ring. Now, is that victory? Of course it is. Wanna know the secret to winning? Creative sportsmanship. In other words, one has to rig the game.</p>"
}
]
}
<dl class="ecl-accordion" role="presentation">
<dt role="heading" aria-level="2">
<button id="ecl-accordion-header-pan1" class="ecl-accordion__header" aria-controls="ecl-accordion-panel-pan1" aria-expanded="false">
<span class="ecl-accordion__header-icon ecl-icon ecl-icon--rounded ecl-u-bg-secondary ecl-icon--growth"></span>
Jobs, Growth, Investment and Competitiveness with an additional quite long string
</button>
</dt>
<dd id="ecl-accordion-panel-pan1" class="ecl-accordion__panel" role="region" aria-labelledby="ecl-accordion-header-pan1" aria-hidden="true">
<p class="ecl-paragraph">Bullfights. Bull hockey. Do you like this? The bull is stabbed, prodded, beaten. The bull is wounded. The bull is tired before the matador ever steps into the ring. Now, is that victory? Of course it is. Wanna know the secret to winning? Creative sportsmanship. In other words, one has to rig the game.</p>
</dd>
<dt role="heading" aria-level="2">
<button id="ecl-accordion-header-pan2" class="ecl-accordion__header" aria-controls="ecl-accordion-panel-pan2" aria-expanded="false">
<span class="ecl-accordion__header-icon ecl-icon ecl-icon--rounded ecl-u-bg-secondary ecl-icon--energy"></span>
Energy Union
</button>
</dt>
<dd id="ecl-accordion-panel-pan2" class="ecl-accordion__panel" role="region" aria-labelledby="ecl-accordion-header-pan2" aria-hidden="true">
<p class="ecl-paragraph">Bullfights. Bull hockey. Do you like this? The bull is stabbed, prodded, beaten. The bull is wounded. The bull is tired before the matador ever steps into the ring. Now, is that victory? Of course it is. Wanna know the secret to winning? Creative sportsmanship. In other words, one has to rig the game.</p>
</dd>
</dl>
-
Content:
// Heavily inspired by the accordion component from https://github.com/frend/frend.co import { queryAll } from '@ecl/ec-base/helpers/dom'; /** * @param {object} options Object containing configuration overrides */ export const accordions = ({ selector: selector = '.ecl-accordion', headerSelector: headerSelector = '.ecl-accordion__header', } = {}) => { // SUPPORTS if ( !('querySelector' in document) || !('addEventListener' in window) || !document.documentElement.classList ) return null; // SETUP // set accordion element NodeLists const accordionContainers = queryAll(selector); // ACTIONS function hidePanel(target) { // get panel const activePanel = document.getElementById( target.getAttribute('aria-controls') ); target.setAttribute('aria-expanded', 'false'); // toggle aria-hidden activePanel.setAttribute('aria-hidden', 'true'); } function showPanel(target) { // get panel const activePanel = document.getElementById( target.getAttribute('aria-controls') ); // set attributes on header target.setAttribute('tabindex', 0); target.setAttribute('aria-expanded', 'true'); // toggle aria-hidden and set height on panel activePanel.setAttribute('aria-hidden', 'false'); } function togglePanel(target) { // close target panel if already active if (target.getAttribute('aria-expanded') === 'true') { hidePanel(target); return; } showPanel(target); } function giveHeaderFocus(headerSet, i) { // set active focus headerSet[i].focus(); } // EVENTS function eventHeaderClick(e) { togglePanel(e.currentTarget); } function eventHeaderKeydown(e) { // collect header targets, and their prev/next const currentHeader = e.currentTarget; const isModifierKey = e.metaKey || e.altKey; // get context of accordion container and its children const thisContainer = currentHeader.parentNode.parentNode; const theseHeaders = queryAll(headerSelector, thisContainer); const currentHeaderIndex = [].indexOf.call(theseHeaders, currentHeader); // don't catch key events when ⌘ or Alt modifier is present if (isModifierKey) return; // catch enter/space, left/right and up/down arrow key events // if new panel show it, if next/prev move focus switch (e.keyCode) { case 13: case 32: togglePanel(currentHeader); e.preventDefault(); break; case 37: case 38: { const previousHeaderIndex = currentHeaderIndex === 0 ? theseHeaders.length - 1 : currentHeaderIndex - 1; giveHeaderFocus(theseHeaders, previousHeaderIndex); e.preventDefault(); break; } case 39: case 40: { const nextHeaderIndex = currentHeaderIndex < theseHeaders.length - 1 ? currentHeaderIndex + 1 : 0; giveHeaderFocus(theseHeaders, nextHeaderIndex); e.preventDefault(); break; } default: break; } } // BIND EVENTS function bindAccordionEvents(accordionContainer) { const accordionHeaders = queryAll(headerSelector, accordionContainer); // bind all accordion header click and keydown events accordionHeaders.forEach(accordionHeader => { accordionHeader.addEventListener('click', eventHeaderClick); accordionHeader.addEventListener('keydown', eventHeaderKeydown); }); } // UNBIND EVENTS function unbindAccordionEvents(accordionContainer) { const accordionHeaders = queryAll(headerSelector, accordionContainer); // unbind all accordion header click and keydown events accordionHeaders.forEach(accordionHeader => { accordionHeader.removeEventListener('click', eventHeaderClick); accordionHeader.removeEventListener('keydown', eventHeaderKeydown); }); } // DESTROY function destroy() { accordionContainers.forEach(accordionContainer => { unbindAccordionEvents(accordionContainer); }); } // INIT function init() { if (accordionContainers.length) { accordionContainers.forEach(accordionContainer => { bindAccordionEvents(accordionContainer); }); } } init(); // REVEAL API return { init, destroy, }; }; // module exports export default accordions;
- URL: /components/raw/ec-component-accordion/ec-component-accordion.js
- Filesystem Path: ../../src/systems/ec/ec-component/ec-component-accordion/ec-component-accordion.js
- Size: 4.4 KB
-
Content:
/** * Accordions * @define accordion */ // Import base and generic @import '@ecl/ec-base/ec-base'; @import '@ecl/generic-component-accordion/generic-component-accordion'; // Check if overridden dependencies are already loaded, if needed @include check-imports(('ec-style-icon')); // Use generic mixin @include exports('ec-component-accordion') { @include ecl-accordion(); }
- URL: /components/raw/ec-component-accordion/ec-component-accordion.scss
- Filesystem Path: ../../src/systems/ec/ec-component/ec-component-accordion/ec-component-accordion.scss
- Size: 382 Bytes
- Handle: @ecl/ec-component-accordion
- Tags: organism
- Preview:
- Filesystem Path: ../../src/systems/ec/ec-component/ec-component-accordion/ec-component-accordion.twig