Auto Close all Details Tags after Opening a Specific One

The details section has been useful to me for a while. It is, without a doubt, the quickest and easiest way to include an accordion on a website. But unlike using a framework to construct accordions, they lack some of the opening/closing behavior that could be anticipated.

Details Tag

Have a look at the details tag:

<details>
  <summary>1</summary>
  Demo 1
</details>

<details>
  <summary>2</summary>
  Demo 2
</details>

<details>
  <summary>3</summary>
  Demo 3
</details>

Solution 1

A little bit quicker and more effective, free of dependencies and HTML onclick properties.

// fetch all the details element.
const details = document.querySelectorAll("details");

// add the onclick listeners.
details.forEach((targetDetail) => {
  targetDetail.addEventListener("click", () => {
    // close all the details that are not targetDetail.
    details.forEach((detail) => {
      if (detail !== targetDetail) {
        detail.removeAttribute("open");
      }
    });
  });
});

Solution 2

Another example without dependency:

const all_details = document.querySelectorAll('details');

all_details.forEach(deet=>{
  deet.addEventListener('toggle', toggleOpenOneOnly)
})

function toggleOpenOneOnly(e) {
  if (this.open) {
    all_details.forEach(deet=>{
      if (deet!=this && deet.open) deet.open = false
    });
  }
}

Solution 3

Shorted example without dependency:

document.querySelectorAll('details').forEach((D,_,A)=>{
  D.ontoggle =_=>{ if(D.open) A.forEach(d =>{ if(d!=D) d.open=false })}
})

Solution 4

Example with jQuery:

$('details').click(function (event) {
    $('details').not(this).removeAttr("open");  
});

Solution 5

Using functional javascript:

[...document.getElementsByTagName("details")].forEach( (D,_,A) =>
  D.addEventListener("toggle", E =>
    D.open && A.forEach(d =>
      d!=E.target && (d.open=false)
    )
  )
)