Accordion

An accordion is like a digital folder that expands and collapses to reveal or hide its contents. It's a nifty tool for organizing information, allowing users to quickly navigate through a website without feeling overwhelmed by a barrage of text. With an accordion, users can easily find what they're looking for, without having to scroll through endless pages of content.

Example

<div class="accordion">
    <div class="item">
        <h4 class="question">
            <button
                type="button"
                aria-expanded="true"
                aria-controls="a1"
            >
                First Amendment
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                     stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="m6 9 6 6 6-6"></path>
                </svg>
            </button>
        </h4>
        <div id="a1" class="answer">
            <p>
                Congress shall make no law respecting an establishment of religion, or
                prohibiting the free exercise thereof; or abridging the freedom of speech,
                or of the press; or the right of the people peaceably to assemble, and to
                petition the Government for a redress of grievances.
            </p>
        </div>
    </div>
    <div class="item">
        <h4 class="question">
            <button
                type="button"
                aria-expanded="true"
                aria-controls="a1"
            >
                First Amendment
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                     stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="m6 9 6 6 6-6"></path>
                </svg>
            </button>
        </h4>
        <div id="a1" class="answer">
            <p>
                Congress shall make no law respecting an establishment of religion, or
                prohibiting the free exercise thereof; or abridging the freedom of speech,
                or of the press; or the right of the people peaceably to assemble, and to
                petition the Government for a redress of grievances.
            </p>
        </div>
    </div>
</div>
@use '~/styles/app.scss' as app;

$accordion: app.get-theme(app.$theme, 'components.accordion');

@include app.generate-component(
  $accordion,
  'accordion',
  app.$config,
  app.$theme
);
const accordion = (elements, options) => {
const defaults = {
accordion_item : ':scope > .item',
question_class : ':scope > .question',
answer_class : ':scope > .answer',
toggle_element : ':scope > .question > button',

show_multiply : false,
a11y : true
};

// Options
const settings = Object.assign({}, defaults, options);

// @TODO Add transitions
// @Add keycodes

const _a11y_checker = () => {
// @TODO Add aria-expanded check
// @TODO Add IDs
}

const _add_event_listeners = (question, answer, toggle_element) => {
toggle_element.addEventListener('click', (e) => {
e.preventDefault();
question.classList.toggle('open');
answer.toggleAttribute('hidden');

if(toggle_element.getAttribute('aria-expanded') !== 'true') {
toggle_element.setAttribute('aria-expanded', 'true');
} else {
toggle_element.setAttribute('aria-expanded', 'false');
}

})
}

const _make_ID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g, (c) => {
let r = (Math.random() * 16) | 0;
let v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
},
);
}

const _init = () => {
// attach classes to buttons and containers
[].forEach.call(elements, (accordion) => {
let accordion_items = accordion.querySelectorAll(settings.accordion_item);
if(accordion_items.length > 0) {
[].forEach.call(accordion_items, (item) => {
_add_event_listeners(
item.querySelector(settings.question_class),
item.querySelector(settings.answer_class),
item.querySelector(settings.toggle_element)
);
})
}
});
}

// Initiating the accordion
if(accordion) {
_init();
}

return ({
elements : elements,
open : () => {}
})
}

const accords = accordion(document.querySelectorAll('.accordion'), {
});

console.log(accords);

Accordion with Schema

<div class="accordion" itemscope itemtype="https://schema.org/FAQPage">
    <div class="item" itemprop="mainEntity" itemscope itemtype="https://schema.org/Question">
        <h4 class="question open">
            <button
                id="question1"
                type="button"
                aria-expanded="true"
                aria-controls="answer1"
                itemprop="name"
            >
                First Amendment
                <svg class="icon" width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M7 14.5L12 9.5L17 14.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </button>
        </h4>
        <div id="answer1" class="answer" itemprop="acceptedAnswer" itemscope
             itemtype="https://schema.org/Answer" role="region" aria-labelledby="question1">
            <p itemprop="text">
                Congress shall make no law respecting an establishment of religion, or
                prohibiting the free exercise thereof; or abridging the freedom of speech,
                or of the press; or the right of the people peaceably to assemble, and to
                petition the Government for a redress of grievances.
            </p>
        </div>
    </div>
    <div class="item" itemprop="mainEntity" itemscope itemtype="https://schema.org/Question">
        <h4 class="question">
            <button
                id="question2"
                type="button"
                aria-expanded="true"
                aria-controls="answer2"
                itemprop="name"
            >
                First Amendment
                <svg class="icon" width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M7 14.5L12 9.5L17 14.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </button>
        </h4>
        <div id="answer2" class="answer" itemprop="acceptedAnswer" itemscope
             itemtype="https://schema.org/Answer" role="region" aria-labelledby="question2" hidden>
            <p itemprop="text">
                Congress shall make no law respecting an establishment of religion, or
                prohibiting the free exercise thereof; or abridging the freedom of speech,
                or of the press; or the right of the people peaceably to assemble, and to
                petition the Government for a redress of grievances.
            </p>
        </div>
    </div>
</div>
@use '~/styles/app.scss' as app;

$accordion: app.get-theme(app.$theme, 'components.accordion');

@include app.generate-component(
  $accordion,
  'accordion',
  app.$config,
  app.$theme
);
const accordion = (elements, options) => {
const defaults = {
accordion_item : ':scope > .item',
question_class : ':scope > .question',
answer_class : ':scope > .answer',
toggle_element : ':scope > .question > button',

show_multiply : false,
a11y : true
};

// Options
const settings = Object.assign({}, defaults, options);

// @TODO Add transitions
// @Add keycodes

const _a11y_checker = () => {
// @TODO Add aria-expanded check
// @TODO Add IDs
}

const _add_event_listeners = (question, answer, toggle_element) => {
toggle_element.addEventListener('click', (e) => {
e.preventDefault();
question.classList.toggle('open');
answer.toggleAttribute('hidden');

if(toggle_element.getAttribute('aria-expanded') !== 'true') {
toggle_element.setAttribute('aria-expanded', 'true');
} else {
toggle_element.setAttribute('aria-expanded', 'false');
}

})
}

const _make_ID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g, (c) => {
let r = (Math.random() * 16) | 0;
let v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
},
);
}

const _init = () => {
// attach classes to buttons and containers
[].forEach.call(elements, (accordion) => {
let accordion_items = accordion.querySelectorAll(settings.accordion_item);
if(accordion_items.length > 0) {
[].forEach.call(accordion_items, (item) => {
_add_event_listeners(
item.querySelector(settings.question_class),
item.querySelector(settings.answer_class),
item.querySelector(settings.toggle_element)
);
})
}
});
}

// Initiating the accordion
if(accordion) {
_init();
}

return ({
elements : elements,
open : () => {}
})
}

const accords = accordion(document.querySelectorAll('.accordion'), {
});

console.log(accords);

Package