Skip to content

Instantly share code, notes, and snippets.

@Kernix13
Last active March 11, 2025 12:11
Show Gist options
  • Save Kernix13/74319ce52f73d25760ea6e07d7dbf90d to your computer and use it in GitHub Desktop.
Save Kernix13/74319ce52f73d25760ea6e07d7dbf90d to your computer and use it in GitHub Desktop.
Animated FAQ accordion
details {
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
padding: 10px;
transition: border 300ms ease-in-out, padding 300ms ease-in-out;
}
details:focus {
outline: 1px solid #CDCDE4;
}
summary {
list-style: none;
cursor: pointer;
font-weight: bold;
position: relative;
padding-right: 20px;
}
summary:focus {
outline: 1px solid transparent;
}
summary::after {
/* Closed state */
content: '+';
font-weight: bold;
font-size: 1.125rem;
color: #0000ff;
position: absolute;
right: 0;
transition: transform 300ms ease-in-out;
}
details[open] summary::after {
content: '−';
/* Open state */
font-weight: bold;
font-size: 1.125rem;
color: #0000ff;
transform: rotate(180deg);
transition: transform 300ms ease-in-out;
}
/* use ▶ instead of + and −
summary::after {
content: '▶';
font-weight: bold;
font-size: 1.125rem;
color: #0000ff;
position: absolute;
right: 0;
transition: transform 300ms ease-in-out;
}
details[open] summary::after {
content: '▼';
font-weight: bold;
font-size: 1.125rem;
color: #0000ff;
transform: rotate(180deg);
transition: transform 300ms ease-in-out;
}
*/
details p {
margin: 0;
padding: 10px 0;
transition: opacity 300ms ease-in-out;
}
<!-- Example DOM structure -->
<div>
<details>
<summary>Question 1?</summary>
<p>Answer one...</p>
</details>
<details>
<summary>Question 2?</summary>
<p>Answer two...</p>
</details>
<details>
<summary>Question 3?</summary>
<p>Answer three...</p>
</details>
</div>
function detailsAccordion() {
const details = document.querySelectorAll('details');
details.forEach(detail => {
const summary = detail.querySelector('summary');
const content = detail.querySelector('p');
// Initial styles
content.style.overflow = 'hidden';
content.style.height = '0px';
content.style.opacity = '0';
content.style.transition = 'height 300ms ease-in-out, opacity 300ms ease-in-out';
summary.addEventListener('click', (e) => {
contentAnimation(e, detail, content);
});
});
}
function contentAnimation(e, parent, child) {
e.preventDefault();
if (parent.hasAttribute('open')) {
// Closing animation
child.style.height = child.scrollHeight + 'px';
requestAnimationFrame(() => {
child.style.height = '0px';
child.style.opacity = '0';
});
setTimeout(() => {
parent.removeAttribute('open');
}, 200);
} else {
// Open animation
parent.setAttribute('open', '');
child.style.height = '0px';
requestAnimationFrame(() => {
child.style.height = child.scrollHeight + 'px';
child.style.opacity = '1';
});
}
}
document.addEventListener('DOMContentLoaded', detailsAccordion);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment