Custom animated disclosure

Recipe 8.3 Create a custom disclosure widget

Sample:

Detailed content goes here…

Detailed content goes here…

Detailed content goes here…

Detailed content goes here…

Detailed content goes here…

Detailed content goes here…

Detailed content goes here…

More content…

Code:

<style>
 .disclosure {
  --_height: 0fr;

  display: grid; 
  justify-content: start;
  grid-template-rows: 1.4rem var(--_height);
}

@media (prefers-reduced-motion: no-preference) {
   .disclosure {
    transition: visibility 0.3s, grid-template-rows 0.3s;
  }
}

 .disclosure > [aria-expanded] {
  width: fit-content;
}

 .disclosure > [aria-expanded="false"] + .disclosure-content {
  visibility: hidden;
}

 .disclosure:has([aria-expanded="true"]) {
  --_height: 1fr;
  grid-template-rows: 1.4rem 1fr;

}

 .disclosure .disclosure-content {
  overflow: hidden;
}
</style>

<div class="disclosure">
  <button aria-expanded="false" aria-controls="content">
    Show details
  </button> 

  <div class="disclosure-content" id="content">
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
    <p>Detailed content goes here…</p>
  </div>
</div>

<p>More content…</p>

<script>
  const button = document.querySelector('button');

  button.addEventListener('click', e => {
    button.setAttribute('aria-expanded', button.getAttribute('aria-expanded') === "false")
  })
</script>