DEV Community

Cover image for Automatically close other details 🚧
LebCit
LebCit

Posted on • Originally published at lebcit.github.io

Automatically close other details 🚧

This post is about closing all <details> tag when another one is open.

I was writing a post about MidDay, my new WordPress Theme, and wanted to include a simple FAQ section but with a little of style, this is when I remembered the <details> tag.

It's an awesome accessible element, similar to an accordion.

How to create one ?

Just follow the pattern in the code.

<details>
  <summary>Summary/Question about the content</summary>
  And here is the content, it could be anything, even code.
  The example is on the original post, can't include <details> here.
</details>
Enter fullscreen mode Exit fullscreen mode

But when we use more than one <details> tag on the same page, especially when they are one after another, we can see that if one is opened and we open another one, the first stays opened.

Imagine having 5 or more after each other, with a reasonable amount of content, they will take a lot of space.
As an example, you can take a look at this informative pen : Teaching the Details Element with ... Details Elements!

So how to close the opened one ?

Easy !
Just include the following code in your scripts file or in a <script> tag at the bottom of your page before the closing </body> tag.

/** Close others <details> tag */
const allDetails = document.querySelectorAll('details');

allDetails.forEach(details => {
    details.addEventListener('toggle', (e) => {
        if (details.open) {
            allDetails.forEach(details => {
                if (details != e.target && details.open) {
                    details.open = false;
                }
            });
        }
    });
});
Enter fullscreen mode Exit fullscreen mode

Let's break it down !

First we select all the <details> tag :

const allDetails = document.querySelectorAll('details');
Enter fullscreen mode Exit fullscreen mode

And we iterate over them :

allDetails.forEach(details => {
Enter fullscreen mode Exit fullscreen mode

Then we listen to the toggle event used by the <details> element whenever its state changes between open and closed :

details.addEventListener('toggle', (e) => {
Enter fullscreen mode Exit fullscreen mode

Now, we wait for any <details> to be open :

if (details.open) {
Enter fullscreen mode Exit fullscreen mode

We iterate once again over all the <details> and check if anyone of them was not the target of the toggle event and was open, if so, we just close it by removing it's open state :

allDetails.forEach(details => {
    if (details != e.target && details.open) {
        details.open = false;
    }
});
Enter fullscreen mode Exit fullscreen mode

In other words, if a <details> element was opened, it have the open attribute. Now if another <details> element is open, we remove the open attribute from the previous, leaving only the actual targeted one opened.

Hope that this was useful, and that you'll start using The Details disclosure element.

SYA,
LebCit.

Discussion (0)