details
summary This is a details element accordion
.content
p Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem maxime beatae amet, enim ducimus debitis quaerat fugiat eaque? Voluptatibus accusantium dicta quaerat ea tempora explicabo blanditiis corrupti inventore asperiores qui?
details
summary This is a details element accordion
.content
p Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem maxime beatae amet, enim ducimus debitis quaerat fugiat eaque? Voluptatibus accusantium dicta quaerat ea tempora explicabo blanditiis corrupti inventore asperiores qui?
details
summary This is a details element accordion
.content
p Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem maxime beatae amet, enim ducimus debitis quaerat fugiat eaque? Voluptatibus accusantium dicta quaerat ea tempora explicabo blanditiis corrupti inventore asperiores qui?
View Compiled
*, *::before, *::after {
box-sizing: border-box;
}
body {
padding: 4rem;
max-width: 48rem;
margin-right: auto;
margin-left: auto;
}
/* Display the <details> element consistently */
details {
display: block;
}
summary {
display: list-item;
}
/* Highlight that the element is interactive */
summary {
cursor: pointer;
}
/* Hide the default twistie */
/* Spec-compliant: */
summary {
list-style-type: none;
}
/* Non-standard: */
summary::-webkit-details-marker {
display: none;
}
/* Display a more common one */
summary {
position: relative;
padding-right: 1.5rem;
}
summary::after {
content: '+';
position: absolute;
top: calc(50% - 0.5em);
right: 0;
}
details[open] summary::after {
content: '-';
}
/* Styling */
details {
border-bottom: 1px solid #eee;
padding: 1rem;
}
:not(details) + details,
details:first-of-type {
border-top: 1px solid #eee;
}
summary {
margin-bottom: 0;
font-weight: 700;
}
summary + * {
margin-top: 1rem;
}
/* Handle animations */
.content {
overflow-y: hidden;
transition: all 0.4s ease;
}
.content.is-closed {
max-height: 0;
margin-top: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
opacity: 0;
}
View Compiled
for (const content of document.querySelectorAll('details .content')) {
content.classList.add('is-closed')
}
const getContentHeight = node => {
// Force node to display properly
node.classList.remove('is-closed')
// Calculate height and store it
node.setAttribute('data-height', `${node.getBoundingClientRect().height}px`)
// Reset node to intiial state
node.classList.add('is-closed')
}
document.addEventListener('click', event => {
if (!event.target.closest('summary')) {
return
}
event.preventDefault()
const accordion = event.target.closest('details')
const content = accordion.querySelector('.content')
// Handle closing
if (accordion.hasAttribute('open')) {
// Animate content out
content.style.removeProperty('max-height')
content.classList.add('is-closed')
// Wait for animation to finish, then remove the `open` attribute
window.setTimeout(() => {
accordion.removeAttribute('open')
}, 400)
// Exit handler
return
}
// Handle opening
// Set the `open` attribute so the content will display
accordion.setAttribute('open', '')
// If our content does not have a calculated height, calculate it
if (!content.hasAttribute('data-height')) {
getContentHeight(content)
}
// Wait a beat for the height to calculate, then animate content in
window.setTimeout(() => {
content.style.maxHeight = content.getAttribute('data-height')
content.classList.remove('is-closed')
}, 0)
})
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.