const initAccordions = () => {
const getNode = selector => document.querySelector(selector),
getNodes = selector => Array.from(document.querySelectorAll(selector)),
findChildren = (node, selector) => Array.from(node.children).filter(e => e.matches?.(selector)),
findChild = (node, selector) => Array.from(node.children).find(e => e.matches?.(selector)),
_addInput = (node, position, id, checked) => node.insertAdjacentHTML(position, `<input type="radio" name="accordion-${id}"${checked ? ' checked="checked"' : ''}>`),
setInnerHeight = node => {
const height = Array.from(node.children).map(child => child.offsetHeight).reduce((a, c) => a + c, 0) + 'px';
node.style.setProperty('--inner-height', height);
},
accordions = Array.from(document.querySelectorAll('.accordion'));
let accordionIndex = 0;
for (const accordion of accordions) {
const isToggle = accordion.dataset?.type === 'toggle',
panels = findChildren(accordion, '.accordion--panel');
let panelIndex = 0;
for (const panel of panels) {
const title = findChild(panel, '.accordion--panel--title'),
content = findChild(panel, '.accordion--panel--content'),
addInput = (node, position, checked) => _addInput(node, position, accordionIndex + (isToggle ? '-' + panelIndex : ''), checked);
setInnerHeight(content);
addInput(title, 'beforebegin');
addInput(title, 'afterbegin', true);
panelIndex++;
}
accordionIndex++;
}
window.addEventListener('resize', () => {
const panelContents = Array.from(document.querySelectorAll('.accordion > .accordion--panel > .accordion--panel--content'));
for (const content of panelContents) setInnerHeight(content);
});
};
initAccordions();
html {
height: 100%;
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
min-height: 100%;
padding: 20px;
}
.accordion--panel > [type=checkbox],
.accordion--panel > [type=radio], .accordion--panel--title > [type=checkbox],
.accordion--panel--title > [type=radio] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.accordion--panel > [type=checkbox]:checked,
.accordion--panel > [type=radio]:checked, .accordion--panel--title > [type=checkbox]:checked,
.accordion--panel--title > [type=radio]:checked {
display: none;
}
.accordion--panel {
border-radius: 7px;
}
.accordion--panel--title {
background-color: #ccc;
}
.accordion--panel--content {
box-shadow: inset 0 0 0 2px #ccc;
border-radius: 0 0 7px 7px;
}
.accordion {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
max-width: 500px;
}
.accordion--panel {
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.accordion--panel > [type=checkbox],
.accordion--panel > [type=radio] {
z-index: 1;
}
.accordion--panel--title, .accordion--panel--content {
padding-inline: 15px;
}
.accordion--panel--title {
position: relative;
padding-block: 10px;
}
.accordion--panel--content {
max-height: 0;
overflow: hidden;
transition: max-height 0.25s cubic-bezier(0.95, 0.05, 0.795, 0.035);
}
.accordion--panel--content--inner > p:first-child {
margin-top: 10px;
}
.accordion--panel--content--inner > p:last-child {
margin-bottom: 10px;
}
[type=checkbox]:checked ~ .accordion--panel--content, [type=radio]:checked ~ .accordion--panel--content {
--content-height: calc(var(--inner-height) + 20px);
max-height: var(--content-height, unset);
}
<h2>Accordion Demo</h2>
<div class="accordion" data-type="accordion">
<div class="accordion--panel">
<div class="accordion--panel--title">Title #1</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet.</p>
</div>
</div>
</div>
<div class="accordion--panel">
<div class="accordion--panel--title">Title #2</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
</div>
</div>
</div>
<div class="accordion--panel">
<div class="accordion--panel--title">Title #3</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
<p>Integer convallis lectus eu felis bibendum, vel lacinia metus imperdiet. Maecenas vulputate, quam vitae tempus pretium, erat felis euismod risus, nec blandit leo mi eget purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at neque laoreet, egestas dui ut, bibendum lorem. Maecenas elementum odio a congue facilisis. Vivamus risus urna, vestibulum egestas sem nec, lacinia volutpat metus. Suspendisse potenti. Suspendisse ullamcorper commodo libero, sed rhoncus nibh porta in. Donec mi felis, posuere luctus varius ac, faucibus vitae erat.</p>
</div>
</div>
</div>
</div>
<h2>Toggle Demo</h2>
<div class="accordion" data-type="toggle">
<div class="accordion--panel">
<div class="accordion--panel--title">Title #1</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet.</p>
</div>
</div>
</div>
<div class="accordion--panel">
<div class="accordion--panel--title">Title #2</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
</div>
</div>
</div>
<div class="accordion--panel">
<div class="accordion--panel--title">Title #3</div>
<div class="accordion--panel--content">
<div class="accordion--panel--content--inner">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
<p>Integer convallis lectus eu felis bibendum, vel lacinia metus imperdiet. Maecenas vulputate, quam vitae tempus pretium, erat felis euismod risus, nec blandit leo mi eget purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at neque laoreet, egestas dui ut, bibendum lorem. Maecenas elementum odio a congue facilisis. Vivamus risus urna, vestibulum egestas sem nec, lacinia volutpat metus. Suspendisse potenti. Suspendisse ullamcorper commodo libero, sed rhoncus nibh porta in. Donec mi felis, posuere luctus varius ac, faucibus vitae erat.</p>
</div>
</div>
</div>
</div>