Accordion
Toggle the visibility of content across your project with a few classes and out additional Javascript plugin (only for accessibility).
How it works#
A radio or checkbox is used to show and hide content. A label with an additional role
attribute is used to trigger a toggle of the div with class .accordion-collapse
. Collapsing an element will animate the max-height
from it’s current value to 0
.
Accordion example#
Using the following syntax, you can use a collapse behavior to create the accordion.
multiple#
<div class="accordion" id="accordion1">
<div class="accordion-item">
<input type="checkbox" data-controller="accordion/input" class="accordion-check sr-only"
id="1ed9426a" name="accordion1_first" checked />
<label type="button" class="accordion-label" for="1ed9426a" id="2bf6c612"
data-target="#c21c8732" aria-expanded="false" aria-controls="c21c8732">
<h5 class="accordion-item-header">Collapsible Group Item #1</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="c21c8732" class="accordion-collapse" aria-labelledby="2bf6c612"
data-parent="#accordion1">Lorem ipsum</div>
</div>
<div class="accordion-item">
<input type="checkbox" data-controller="accordion/input" class="accordion-check sr-only"
id="87a835a4" name="accordion1_second" />
<label type="button" class="accordion-label" for="87a835a4" id="e526f217"
data-target="#fd436328" aria-expanded="false" aria-controls="fd436328">
<h5 class="accordion-item-header">Collapsible Group Item #2</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="fd436328" class="accordion-collapse" aria-labelledby="e526f217"
data-parent="#accordion1">Lorem ipsum</div>
</div>
<div class="accordion-item">
<input type="checkbox" data-controller="accordion/input" class="accordion-check sr-only"
id="9d6254d2" name="accordion1_third" disabled />
<label type="button" class="accordion-label" for="9d6254d2" id="528eeeec"
data-target="#a65a90ac" aria-expanded="false" aria-controls="a65a90ac">
<h5 class="accordion-item-header">Collapsible Group Item #3</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="a65a90ac" class="accordion-collapse" aria-labelledby="528eeeec"
data-parent="#accordion1">Lorem ipsum</div>
</div>
</div>
import "./cakeDOM";
if (typeof window.cake !== "object") {
window.cake = {};
}
const defaultOptions = {
elements: [],
querySelector: '*[data-controller="accordion/input"]'
};
window.cake.accordion = (options = defaultOptions) => {
options = {
...defaultOptions,
...options
};
//Get All Accordion-Inputs and set Event-Listener (change)
let accordionInputElements = window.cake.utils.getElements(options.elements, options
.querySelector);
accordionInputElements.forEach((accordionInputElement) => {
accordionInputElement.addEventListener('change', () => {
let accordionInputLabel = accordionInputElement.nextSibling;
//Toggle aria-expanded on all other elements, when input is radio (single-variant)
if (accordionInputElement.getAttribute('type') === 'radio') {
const accordionInputLabelElement = accordionInputElement
.parentElement.siblingSelector('label[aria-expanded=true]');
if (accordionInputLabelElement) {
accordionInputLabelElement.setAttribute('aria-expanded',
false);
}
}
accordionInputLabel.setAttribute('aria-expanded',
accordionInputLabel.getAttribute('aria-expanded') ==
"false" ? true : false);
});
})
};
export default window.cake.accordion;
Instead of a type="checkbox"
you can simply use the type="radio"
to make only a single accordion-item extensible at once.
If you wantan accordion-item to be extended on page load, simply set the input
to checked
.
single#
<div class="accordion" id="accordion2">
<div class="accordion-item">
<input type="radio" data-controller="accordion/input" class="accordion-check sr-only"
id="d4d4c845" name="accordion2_input" checked />
<label type="button" class="accordion-label" for="d4d4c845" id="2c3d33de"
data-target="#b7923d87" aria-expanded="false" aria-controls="b7923d87">
<h5 class="accordion-item-header">Collapsible Group Item #1</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="b7923d87" class="accordion-collapse" aria-labelledby="2c3d33de"
data-parent="#accordion2">Lorem ipsum</div>
</div>
<div class="accordion-item">
<input type="radio" data-controller="accordion/input" class="accordion-check sr-only"
id="ecaea25e" name="accordion2_input" />
<label type="button" class="accordion-label" for="ecaea25e" id="86f66cb8"
data-target="#7d8e8453" aria-expanded="false" aria-controls="7d8e8453">
<h5 class="accordion-item-header">Collapsible Group Item #2</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="7d8e8453" class="accordion-collapse" aria-labelledby="86f66cb8"
data-parent="#accordion2">Lorem ipsum</div>
</div>
<div class="accordion-item">
<input type="radio" data-controller="accordion/input" class="accordion-check sr-only"
id="17aae0c0" name="accordion2_input" disabled />
<label type="button" class="accordion-label" for="17aae0c0" id="d68e51ff"
data-target="#bb64f623" aria-expanded="false" aria-controls="bb64f623">
<h5 class="accordion-item-header">Collapsible Group Item #3</h5>
<svg class="icon accordion-icon" xmlns="http://www.w3.org/2000/svg" role="img"
focusable="false">
<title>Expand</title>
<use xlink:href="../../.././_assets/images/icon__sprite.svg#arrow-down">
</use>
</svg>
</label>
<div id="bb64f623" class="accordion-collapse" aria-labelledby="d68e51ff"
data-parent="#accordion2">Lorem ipsum</div>
</div>
</div>
import "./cakeDOM";
if (typeof window.cake !== "object") {
window.cake = {};
}
const defaultOptions = {
elements: [],
querySelector: '*[data-controller="accordion/input"]'
};
window.cake.accordion = (options = defaultOptions) => {
options = {
...defaultOptions,
...options
};
//Get All Accordion-Inputs and set Event-Listener (change)
let accordionInputElements = window.cake.utils.getElements(options.elements, options
.querySelector);
accordionInputElements.forEach((accordionInputElement) => {
accordionInputElement.addEventListener('change', () => {
let accordionInputLabel = accordionInputElement.nextSibling;
//Toggle aria-expanded on all other elements, when input is radio (single-variant)
if (accordionInputElement.getAttribute('type') === 'radio') {
const accordionInputLabelElement = accordionInputElement
.parentElement.siblingSelector('label[aria-expanded=true]');
if (accordionInputLabelElement) {
accordionInputLabelElement.setAttribute('aria-expanded',
false);
}
}
accordionInputLabel.setAttribute('aria-expanded',
accordionInputLabel.getAttribute('aria-expanded') ==
"false" ? true : false);
});
})
};
export default window.cake.accordion;
Accessibility#
Be sure to add aria-expanded
to the label element. This attribute explicitly conveys the current state of the collapsible element tied to the control to screen readers and similar assistive technologies. If the collapsible element is closed by default, the attribute on the control element should have a value of aria-expanded="false"
. If you’ve set the collapsible element to be open by default set aria-expanded="true"
on the control instead. The plugin will automatically toggle this attribute on the control based on whether or not the collapsible element has been opened or closed (via Javascript).
If your control element is targeting a single collapsible element – i.e. the data-target
attribute is pointing to an id
selector – you should add the aria-controls
attribute to the control element, containing the id
of the collapsible element. Modern screen readers and similar assistive technologies make use of this attribute to provide users with additional shortcuts to navigate directly to the collapsible element itself.
JavaScript#
The accordion does work without javascript. But to ensure best accessibility we've created a small script to set the aria-expanded="true"
to it's correct state on user interaction.
You can import our javascript bundle cake.js
to automatically use this feature. You only must ensure that the property data-controller="accrodion/collapse"
is set on the input element of the accordion.
Initialization#
To initialize the javascript with default configuration you could simply run the following code:
document.addEventListener ('DOMContentLoaded', () => {
window.cake.accordion ();
});
Customization#
To customize the default behavior you can only embedd the accordion.js
file into your mockups. Then you can initialize the functionality by calling:
document.addEventListener ('DOMContentLoaded', () => {
window.cake.accordion (options = {
elements: [],
querySelector: '*[data-controller="accordion/input"]'
});
});
elements [Array]
– provide the specific input elements of your accordion (optional)querySelector [String]
– provide a query-selector to select all accordion input elements in your DOM (optional, default:*[data-controller="accordion/input"]
)
If you do provide the options.elements
the options.querySelector
option gets ignored. If you do not provide any options.elements
always the options.querySelector
is used!
Change log#
Added#
Doc
: "Accordion" | added javaScript file content as "JS" tab
Added#
SCSS
: "Accordion" | addedmargin-left
to the icon, to match the design requirementsSCSS
: "Accordion" | Addedoverflow: hidden
andtext-overflow: ellipsis
to the accordion label to hide too much content.
Fixed#
SCSS
: "Accordion" | fixedmargin-top
between accordion elements to be exact 8px
Changed#
JS
,Doc
: "Accordion" | updated javascript to provideoptions
object for better integration of CAKEHTML
,Doc
: "Accordion" | refactoreddata-toggle=accordion-collapse
todata-controller="accordion/input"
SCSS
: "Accordion" | add new variables$accordion-max-height
and$accordion-padding-y
Changed#
SCSS
: "Accordion" | added new height for xs-md
Added#
SCSS
: "Accordion" | Transitions are configurable in thevariables.scss
file
Changed#
SCSS
: "Accordion" | Icon transition is now configurable$accordion-icon-transition
SCSS
: "Accordion" | Use mixins for border radius and transition