Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Last active May 21, 2024 04:11
Show Gist options
  • Save cferdinandi/054ba5806332d5aa2e8f69f4e3689308 to your computer and use it in GitHub Desktop.
Save cferdinandi/054ba5806332d5aa2e8f69f4e3689308 to your computer and use it in GitHub Desktop.
/**
* Style the accordion buttons to look like headers
*/
accordion-group [trigger] > button {
background: transparent;
border: none;
display: block;
font: inherit;
margin: 0;
padding: 0;
text-align: left;
width: 100%;
}
/**
* Show expand/collapse icons
*/
accordion-group [trigger] > button[aria-expanded="true"]::after {
content: " -";
}
accordion-group [trigger] > button[aria-expanded="false"]::after {
content: " +";
}
customElements.define('accordion-group', class extends HTMLElement {
/**
* Instantiate the Web Component
*/
constructor () {
// Get parent class properties
super();
// Set properties
this.headings = this.getAttribute('headings');
this.exclusive = this.hasAttribute('exclusive');
// Setup UI
this.setup();
}
/**
* Handle Events
* @param {Event} event The event object
*/
handleEvent (event) {
// Only run on accordion triggers
let trigger = event.target.closest('[trigger]');
if (!trigger) return;
let btn = trigger.firstElementChild;
// Get the content associated with the accordion
let content = trigger.nextElementSibling;
if (!content) return;
// If the content is expanded, hide it
// Otherwise, show it
if (btn.getAttribute('aria-expanded') === 'true') {
btn.setAttribute('aria-expanded', false);
content.setAttribute('hidden', '');
} else {
btn.setAttribute('aria-expanded', true);
content.removeAttribute('hidden');
}
// If not exclusive, all set
if (!this.exclusive) return;
// Otherwise, hide all other open accordions
let openAccordions = this.querySelectorAll('[trigger] > [aria-expanded="true"]');
for (let accordion of openAccordions) {
if (accordion === btn) continue;
accordion.setAttribute('aria-expanded', false);
accordion.parentNode.nextElementSibling.setAttribute('hidden', '');
}
}
/**
* Add buttons and hide content on page load
*/
setup () {
// Get all accordion headings
let headings = this.querySelectorAll(this.headings);
// Update content
for (let heading of headings) {
// Get the matching content
let content = heading.nextElementSibling;
if (!content) continue;
// Create a button, and copy heading content into it
let btn = document.createElement('button');
btn.innerHTML = heading.innerHTML;
// Wipe the heading content, and replace it with the button
heading.innerHTML = '';
heading.append(btn);
heading.setAttribute('trigger', '');
// Hide the content
content.setAttribute('hidden', '');
// Add ARIA
btn.setAttribute('aria-expanded', false);
}
// Listen for click events
this.addEventListener('click', this);
}
});
<!DOCTYPE html>
<html>
<head>
<title>Accordions</title>
<style type="text/css">
body {
margin: 1em auto;
max-width: 30em;
width: 88%;
}
</style>
<link rel="stylesheet" type="text/css" href="accordion-group.css">
</head>
<body>
<h1>Accordions</h1>
<accordion-group headings="h2">
<h2>Yo, ho ho!</h2>
<div>Yo, ho ho and a bottle of rum!</div>
<h2>Ahoy, there!</h2>
<div>Ahoy there, matey!</div>
</accordion-group>
<script src="accordion-group.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment