<div class="bux-accordion" data-allow-multiple>
<h3 class="bux-accordion__heading">
<button id="bux-accordion__trigger--1" type="button" class="bux-accordion__trigger" aria-controls="bux-accordion__panel--1" aria-expanded="false">
<span class="bux-accordion__icon" aria-hidden="true"></span>
<span class="bux-accordion__title">
Title of Accordion
</span>
</button>
</h3>
<div id="bux-accordion__panel--1" class="bux-accordion__panel" role="region" aria-labelledby="bux-accordion__trigger--1" hidden>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
<h3 class="bux-accordion__heading">
<button id="bux-accordion__trigger--2" type="button" class="bux-accordion__trigger" aria-controls="bux-accordion__panel--2" aria-expanded="false">
<span class="bux-accordion__icon" aria-hidden="true"></span>
<span class="bux-accordion__title">
Title of Accordion
</span>
</button>
</h3>
<div id="bux-accordion__panel--2" class="bux-accordion__panel" role="region" aria-labelledby="bux-accordion__trigger--2" hidden>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
<h3 class="bux-accordion__heading">
<button id="bux-accordion__trigger--3" type="button" class="bux-accordion__trigger" aria-controls="bux-accordion__panel--3" aria-expanded="false">
<span class="bux-accordion__icon" aria-hidden="true"></span>
<span class="bux-accordion__title">
Title of Accordion
</span>
</button>
</h3>
<div id="bux-accordion__panel--3" class="bux-accordion__panel" role="region" aria-labelledby="bux-accordion__trigger--3" hidden>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>
{#
Accordion
Available variables:
- modifier: Sets the type of accordion. 'default' or 'details'.
- heading_level: Integer value that sets the heading level of the title.
- items: An array containing the accordion items.
- item.id: Unique id for the accordion.
- item.title: Title of the accordion.
- item.content: Content of the accordion.
#}
{% if modifier == "default" %}
<div class="bux-accordion" data-allow-multiple>
{% for item in items %}
{% set triggerId = "bux-accordion__trigger--" ~ item.id %}
{% set panelId = "bux-accordion__panel--" ~ item.id %}
<h{{heading_level|default("2")}} class="bux-accordion__heading">
<button id="{{ triggerId }}" type="button" class="bux-accordion__trigger" aria-controls="{{ panelId }}" aria-expanded="false">
<span class="bux-accordion__icon" aria-hidden="true"></span>
<span class="bux-accordion__title">
{{ item.title }}
</span>
</button>
</h{{heading_level|default("2")}}>
<div id="{{ panelId }}" class="bux-accordion__panel" role="region" aria-labelledby="{{ triggerId }}" hidden>
{{ item.content }}
</div>
{% endfor %}
</div>
{% elseif modifier == "details" %}
{% for item in items %}
<div class="bux-details__wrapper">
<details class="bux-details">
<summary class="bux-details__summary">{{ item.title }}</summary>
<div class="bux-details__inner">
{{ item.content }}
</div>
</details>
</div>
{% endfor %}
{% endif %}
site_name_prefix: Office of
site_name: Learning Relations Excellence
site_slogan: Additional text or site slogan
address_1: 100 Building Name
address_2: 1 Oval Mall
city: Columbus
state: OH
zip: '43210'
contact_email: email@osu.edu
contact_phone: 614-292-OHIO
contact_tty: 614-688-8605
heading_level: 3
items:
'1':
id: 1
title: Title of Accordion
content: >-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
'2':
id: 2
title: Title of Accordion
content: >-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
'3':
id: 3
title: Title of Accordion
content: >-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
modifier: default
.bux-accordion {
border-bottom: 2px solid $gray-light-80;
}
.bux-accordion__heading {
margin-bottom: 0;
}
.bux-accordion__trigger {
@include button-reset;
color: $gray-dark-80;
background-color: $white;
border-top: 2px solid $gray-light-80;
padding: $sp-16;
width: 100%;
text-align: left;
position: relative;
&:focus,
&:hover {
color: $gray-dark-80;
background: $gray-light-90;
border: none;
border-top: 2px solid $gray-light-80;
}
&:focus {
outline: 2px solid $focus;
outline-offset: -2px;
}
}
.bux-accordion__trigger[aria-expanded="true"] {
background: $white;
&:hover {
background: $gray-light-90;
}
}
.bux-accordion__title {
font-size: $ts-base;
display: block;
pointer-events: none;
font-weight: 700;
padding-left: rem-calc(26);
}
.bux-accordion__icon:before {
position: absolute;
color: $scarlet;
font-size: $ts-base;
left: $sp-16;
top: 36%;
content: "\f005";
font-family: $icon;
}
.bux-accordion__trigger[aria-expanded="true"] .bux-accordion__icon:before {
content: "\f007";
}
.bux-accordion__panel {
margin: 0;
padding: rem-calc(8 16 24 44);
font-family: $sans;
font-size: $ts-base;
background-color: $white;
p {
font-family: $sans;
}
}
/* For Edge bug https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4806035/ */
.bux-accordion__panel[hidden] {
display: none;
}
/* Fix for accordion list font family */
.bux-accordion ul.bux-list-ul {
font-family: $sans;
}
.bux-details {
width: 100%;
text-align: left;
}
.bux-details__summary {
list-style: none;
border-top: none;
border-bottom: 2px solid $gray-light-80;
padding: $sp-16;
font-size: $ts-base;
font-weight: 700;
line-height: normal;
&:focus,
&:hover {
background: $gray-light-90;
}
&:focus {
outline-offset: -2px;
outline: 2px solid $focus;
}
&:before {
position: relative;
top: 2px;
margin-right: rem-calc(10);
color: $scarlet;
font-size: $ts-base;
content: "\f005";
font-family: $icon;
}
}
.bux-details__wrapper .bux-detail:first-child .bux-details__summary {
border-top: 2px solid $gray-light-80;
}
.bux-details__inner {
padding: rem-calc(8 16 24 44);
ul.bux-list-ul {
font-family: $sans;
}
p:last-child {
margin-bottom: 0;
}
}
// When open.
.bux-details[open] {
border-bottom: 2px solid $gray-light-80;
.bux-details__summary {
background: $white;
border-bottom: none;
&:hover {
background: $gray-light-90;
}
&:before {
content: "\f007";
}
}
}
// Fix for double arrow in Safari
*::-webkit-details-marker {
display: none;
}
const accordionClass = "bux-accordion";
let accordions = document.querySelectorAll(`.${accordionClass}`);
accordions = Array.prototype.slice.call(accordions);
accordions.forEach((accordion) => {
let triggers = accordion.querySelectorAll(`.${accordionClass}__trigger`);
triggers = Array.prototype.slice.call(triggers);
let panels = accordion.querySelectorAll(`.${accordionClass}__panel`);
panels = Array.prototype.slice.call(panels);
triggers.forEach((trigger) => {
trigger.addEventListener("keydown", handleKeys);
trigger.addEventListener("click", (event) => {
const { currentTarget: currentTrigger } = event;
if (!allowMultipleOpen(currentTrigger)) {
closeAccordionItems(currentTrigger, triggers, panels);
}
toggleAccordionItem(currentTrigger);
});
});
});
function handleKeys(event) {
const {
key: currentKey,
currentTarget: currentTrigger,
currentTarget: {
parentNode: { parentNode: currentAccordion },
},
} = event;
let triggers = currentAccordion.querySelectorAll(`.${accordionClass}__trigger`);
triggers = Array.prototype.slice.call(triggers);
const currentTriggerIndex = triggers.indexOf(currentTrigger);
switch (currentKey) {
case keys.up:
if (currentTriggerIndex === 0) {
triggers[triggers.length - 1].focus();
} else {
triggers[currentTriggerIndex - 1].focus();
}
event.preventDefault();
break;
case keys.down:
if (currentTriggerIndex === triggers.length - 1) {
triggers[0].focus();
} else {
triggers[currentTriggerIndex + 1].focus();
}
event.preventDefault();
break;
case keys.home:
triggers[0].focus();
event.preventDefault();
break;
case keys.end:
triggers[triggers.length - 1].focus();
event.preventDefault();
break;
}
}
function isHeading(element) {
return element && element.classList.contains(`${accordionClass}__heading`);
}
function toggleAccordionItem(element) {
let currentTriggerExpanded = element.getAttribute("aria-expanded");
currentTriggerExpanded = currentTriggerExpanded === "true" ? true : false;
element.setAttribute("aria-expanded", !currentTriggerExpanded);
const currentPanelId = element.getAttribute("aria-controls");
const currentPanel = document.querySelector(`#${currentPanelId}`);
let currentPanelHidden = currentPanel.getAttribute("hidden");
if (currentPanelHidden !== null) {
currentPanel.removeAttribute("hidden");
} else {
currentPanel.setAttribute("hidden", "hidden");
}
}
function allowMultipleOpen(element) {
const {
parentNode: { parentNode: currentAccordion },
} = element;
const {
dataset: { allowMultiple: hasAllowMultiple },
} = currentAccordion;
return hasAllowMultiple !== undefined ? true : false;
}
function closeAccordionItems(trigger, triggers, panels) {
const otherTriggers = triggers.filter((element) => element !== trigger);
otherTriggers.forEach((otherTrigger) => {
otherTrigger.setAttribute("aria-expanded", false);
});
const currentPanelId = trigger.getAttribute("aria-controls");
const currentPanel = document.querySelector(`#${currentPanelId}`);
const otherPanels = panels.filter((element) => element !== currentPanel);
otherPanels.forEach((otherPanel) => {
otherPanel.setAttribute("hidden", "hidden");
});
}
This component is based on the guidelines laid out in the W3’s example, Accordion Example.
Key | Fuction |
---|---|
Space or Enter |
When focus is on the accordion header of a collapsed section, expands the section. |
Tab |
|
Shift + Tab |
|
Down Arrow |
|
Up Arrow |
|
Home |
When focus is on an accordion header, moves focus to the first accordion header. |
End |
When focus is on an accordion header, moves focus to the last accordion header. |
data-allow-multiple
— By adding this data attribute to the accordion multiple accordion items can be open at any given time.