Skip to content

Instantly share code, notes, and snippets.

@undfine
Created July 16, 2025 17:35
Show Gist options
  • Select an option

  • Save undfine/60d2b62fb5320b77836975618bdf0190 to your computer and use it in GitHub Desktop.

Select an option

Save undfine/60d2b62fb5320b77836975618bdf0190 to your computer and use it in GitHub Desktop.
Create accordion from sections
document.addEventListener('DOMContentLoaded', () => {
/**
* Sets up accordion functionality within a given container element.
* Finds sections based on a selector, wraps them and their subsequent content,
* and adds toggle functionality.
* @param {HTMLElement} container The HTML element acting as the accordion container.
* @param {string} sectionSelector The CSS selector for the elements that will act as section titles (e.g., 'h2', 'h3', '.my-title-class').
*/
function setupAccordion(container, sectionSelector = 'h2') { // Default to 'h2'
// Query sections within this specific container using the provided selector
const sections = container.querySelectorAll(sectionSelector);
sections.forEach(section => {
// Create a slug from the section's text content for use as an ID
const sectionText = section.textContent;
const idSlug = sectionText
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
// Add the new class to the section title
section.classList.add('accordion-title');
// Create the main accordion item container
const accordionItem = document.createElement('div');
accordionItem.classList.add('accordion-item');
// Create the accordion content div
const accordionContent = document.createElement('div');
accordionContent.classList.add('accordion-content');
accordionContent.hidden = true; // Initial state: content is hidden by default
accordionContent.id = `accordion-content-${idSlug}`; // Set the ID for the content
// Move sibling elements into the accordion content until the next section title or end of document
let currentElement = section.nextElementSibling;
while (currentElement && !currentElement.matches(sectionSelector)) {
accordionContent.appendChild(currentElement);
currentElement = section.nextElementSibling; // Get the *new* next sibling
}
// Insert the accordion item right before the section title in its original parent
section.parentNode.insertBefore(accordionItem, section);
// Then, move the section title and the accordionContent into the accordionItem
accordionItem.appendChild(section);
accordionItem.appendChild(accordionContent);
// Add event listener to the section title for toggling
section.addEventListener('click', () => {
const isActive = accordionItem.classList.toggle('active');
// Toggle ARIA attributes for accessibility
section.setAttribute('aria-expanded', isActive);
accordionContent.setAttribute('aria-hidden', !isActive);
accordionContent.hidden = !isActive;
});
// Set initial ARIA attributes for accessibility
section.setAttribute('role', 'button');
section.setAttribute('tabindex', '0');
section.setAttribute('aria-controls', accordionContent.id);
accordionContent.setAttribute('aria-hidden', 'true');
});
}
// --- Main Execution ---
// Find all containers that should be accordions
const accordionContainers = document.querySelectorAll('.make-accordion');
// Setup each container as an accordion
accordionContainers.forEach(container => {
// You can now pass the desired selector for each container
// If not provided, it will default to 'h2' as defined in the function signature.
// Example: setupAccordion(container, 'h3'); // If you want to use h3s as titles in this container
setupAccordion(container); // Uses default 'h2' for all .make-accordion containers
});
// Example of setting up an accordion with h3s in a specific container:
// If you had a container like <div id="my-h3-accordion" class="make-accordion">
// const h3AccordionContainer = document.getElementById('my-h3-accordion');
// if (h3AccordionContainer) {
// setupAccordion(h3AccordionContainer, 'h3');
// }
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment