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

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.