Accordion (Multiselect)
Accordion (Multiselect)
Turn on a screen reader to experience this example in action.
Non-functional link, for testing purposes
HTML Source Code
<!--
This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License https://www.w3.org/copyright/software-license-2023/
-->
<div id="accordionGroup" class="accordion">
<h2>
<button type="button"
aria-expanded="true"
class="accordion-trigger"
aria-controls="sect1"
id="accordion1id">
<span class="accordion-title">
Prospective Students
<span class="accordion-icon"></span>
</span>
</button>
</h2>
<div id="sect1"
role="region"
aria-labelledby="accordion1id"
class="accordion-panel">
<ul>
<li><a href="#">Prospective Students Home Page</a></li>
<li><a href="#">Admissions</a></li>
<li><a href="#">Financing Your Education</a></li>
</ul>
</div>
<h2>
<button type="button"
aria-expanded="false"
class="accordion-trigger"
aria-controls="sect2"
id="accordion2id">
<span class="accordion-title">
Students
<span class="accordion-icon"></span>
</span>
</button>
</h2>
<div id="sect2"
role="region"
aria-labelledby="accordion2id"
class="accordion-panel"
hidden="">
<ul>
<li><a href="#">Students Home Page</a></li>
<li><a href="#">Records</a></li>
<li><a href="#">Student Life</a></li>
<li><a href="#">Student Organizations</a></li>
<li><a href="#">Technology</a></li>
<li><a href="#">Library</a></li>
</ul>
</div>
<h2>
<button type="button"
aria-expanded="false"
class="accordion-trigger"
aria-controls="sect3"
id="accordion3id">
<span class="accordion-title">
Faculty
<span class="accordion-icon"></span>
</span>
</button>
</h2>
<div id="sect3"
role="region"
aria-labelledby="accordion3id"
class="accordion-panel"
hidden="">
<ul>
<li><a href="#">Faculty Home</a></li>
<li><a href="#">Directory</a></li>
<li><a href="#">News</a></li>
<li><a href="#">Publications</a></li>
</ul>
</div>
<h2>
<button type="button"
aria-expanded="false"
class="accordion-trigger"
aria-controls="sect4"
id="accordion4id">
<span class="accordion-title">
Alumni
<span class="accordion-icon"></span>
</span>
</button>
</h2>
<div id="sect4"
role="region"
aria-labelledby="accordion4id"
class="accordion-panel"
hidden="">
<ul>
<li><a href="#">Alumni Home Page</a></li>
<li><a href="#">Benefits and Services</a></li>
<li><a href="#">Giving</a></li>
<li><a href="#">Alumni Association</a></li>
<li><a href="#">Volunteer Opportunities</a></li>
</ul>
</div>
</div>
JavaScript Source Code
Dependencies:
- JQuery
//This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License https://www.w3.org/copyright/software-license-2023/
if( typeof TabAccordion === "undefined")
{
var TabAccordions = [];
class TabAccordion {
static openedEle = null;
constructor(domNode, multiple ) {
if (typeof multiple == "undefined") multiple=true;
if (typeof multiple == "boolean") this.multiple = multiple;
this.rootEl = domNode;
this.buttonEl = this.rootEl.querySelector('button[aria-expanded]');
if ( this.buttonEl == null)
{
console.log("button and/or aria-expanded attribute is missing.");
return null;
}
const controlsId = this.buttonEl.getAttribute('aria-controls');
this.contentEl = document.getElementById(controlsId);
this.open = this.buttonEl.getAttribute('aria-expanded') === 'true';
this.closeActiveTab();
// add event listeners
this.buttonEl.addEventListener('click', this.onButtonClick.bind(this));
}
onButtonClick() {
this.toggle(!this.open);
}
toggle(open) {
// don't do anything if the open state doesn't change
if (open === this.open) {
return;
}
// update the internal state
this.open = open;
// handle DOM updates
this.buttonEl.setAttribute('aria-expanded', `${open}`);
if (open) {
this.contentEl.removeAttribute('hidden');
} else {
this.contentEl.setAttribute('hidden', '');
}
this.closeActiveTab();
//this.closeOthers();
}
closeActiveTab()
{
if (this.multiple ) return;
if(this.open)
{
if( TabAccordion.openedEle != null )
{
TabAccordion.openedEle.contentEl.setAttribute('hidden', '');
TabAccordion.openedEle.open = false;
TabAccordion.openedEle.buttonEl.setAttribute('aria-expanded', 'false');
}
TabAccordion.openedEle = this;
}
else
{
if(this == TabAccordion.openedEle)
TabAccordion.openedEle = null;
}
}
closeOthers()
{
const accordions = document.querySelectorAll('.accordion h2');
TabAccordions.forEach((accordionEl) => {
//let tab = new TabAccordion(accordionEl);
let tab = accordionEl;
console.log("tab id:"+ tab.contentEl.id);
console.log("target id:"+ this.contentEl.id);
if (tab.contentEl.id !== this.contentEl.id)
{
//accordionEl.setAttribute('hidden', '');
tab.close();
}
});
}
// Add public open and close methods for convenience
open() {
this.toggle(true);
}
close() {
this.toggle(false);
}
}
// init accordions
const accordions = document.querySelectorAll('.accordion h2');
accordions.forEach((accordionEl) => {
var tab = new TabAccordion(accordionEl);
TabAccordions.push(tab);
});
}
CSS Source Code
/*
This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License https://www.w3.org/copyright/software-license-2023/
*/
.accordion {
margin: 0;
padding: 0;
border: 2px solid hsl(0deg 0% 52%);
border-radius: 7px;
width: 20em;
}
.accordion h2 {
margin: 0;
padding: 0;
}
.accordion:focus-within {
border-color: hsl(216deg 94% 43%);
}
.accordion:focus-within h2 {
background-color: hsl(0deg 0% 97%);
}
.accordion > * + * {
border-top: 1px solid hsl(0deg 0% 52%);
}
.accordion-trigger {
background: #375898;
color: white;
display: block;
font-weight: bold;
font-size: 1rem;
width: 100%;
margin: 0;
padding: 1em 1.5em;
position: relative;
text-align: left;
outline: none;
}
.accordion-trigger:focus,
.accordion-trigger:hover {
background: hsl(216deg 94% 94%);
color: black;
}
.accordion-trigger:focus {
outline: 4px solid transparent;
}
.accordion > *:first-child .accordion-trigger,
.accordion > *:first-child {
border-radius: 5px 5px 0 0;
}
.accordion > *:last-child .accordion-trigger,
.accordion > *:last-child {
border-radius: 0 0 5px 5px;
}
button {
border-style: none;
}
.accordion button::-moz-focus-inner {
border: 0;
}
.accordion-title {
display: block;
pointer-events: none;
border: transparent 2px solid;
border-radius: 5px;
padding: 0.25em;
outline: none;
}
.accordion-trigger:focus .accordion-title {
border-color: hsl(216deg 94% 43%);
}
.accordion-icon {
border: solid currentcolor;
border-width: 0 2px 2px 0;
height: 0.5rem;
pointer-events: none;
position: absolute;
right: 2em;
top: 50%;
transform: translateY(-60%) rotate(45deg);
width: 0.5rem;
}
.accordion-trigger:focus .accordion-icon,
.accordion-trigger:hover .accordion-icon {
border-color: hsl(216deg 94% 43%);
}
.accordion-trigger[aria-expanded="true"] .accordion-icon {
transform: translateY(-50%) rotate(-135deg);
}
.accordion-panel {
margin: 0;
/* padding: 1em 1.5em; */
}
/* For Edge bug https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4806035/ */
.accordion-panel[hidden] {
display: none;
}
.accordion div.tab:focus {
background-color: #566ac8;
/* outline: 2px solid #8cc63f; */
outline: 3px solid #467310;
}
.accordion > li:hover {
cursor: pointer;
}
.accordion div.tab {
background: #375898;
border: 1px solid #fff;
color: #fff;
padding: 3px 6px;
}
.tablist div.tab.active {
font-weight: bold;
}
.accordion-panel .inactive {
display: none;
}
.accordion-panel ul {
margin: 0;
padding: 0;
}
.accordion-panel li a {
text-decoration: none;
}
.accordion-panel li {
list-style-type: none;
background:#fff;
border-bottom:1px dashed #375898;
color:#375898;
margin: 0;
padding: 5px;
}
.accordion-panel li:last-child {
border-bottom: none;
}