javascriptjqueryhtml-tag-detailshtml-tag-summary

<details> opens one after another with a shortcut


I tried to set it up when pressing a "a" key to open in order, but it opens all at the same time.

Expected outcome:

  1. "a" key = open Details1
  2. "a" key = open Details2
  3. "a" key = open Details3

document.onkeyup = function(e) {
    var e = e || window.event;
    if (e.which == 65) {
        $('details').attr('open', true);
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<details>
    <summary>Details1</summary>
    test1
    
    <details>
        <summary>Details2</summary>
    test2
    
        <details>
            <summary>Details3</summary>
    test3

        </details>
    </details>
</details>


Solution

  • this way
    For information, the details elements work with a toggle event
    and their open attribute type is Boolean.

    For more explanation please referto my answer there

    // array of details elements in hierarchical order
    const details_tree = [...document.querySelectorAll('body>details, body>details>details, body>details>details>details')] 
    
    document.onkeydown=e=>
      {
      if (e.key==='a')                   // open part 
      for (let D of details_tree)       // loop to find  
      if (!D.open)                     // the first closed (not open)
        {
        D.open = true                 // open it
        break                        // break the loop
        }
      if (e.key==='b')                       // close part
      for (let i=details_tree.length;i--;)  // reverse loop to find  
      if (details_tree[i].open)            // the last open 
        {
        details_tree[i].open = false      // close it
        break                            // break the loop 
        }
      }
     
    // option : when closing a <detail> element, sub <details> will be closed too
    details_tree.forEach((D,index,A)=>{
      D.ontoggle =_=>{ if(!D.open) A.forEach((d,i)=>{ if(i>index) d.open=false })}
    })
    details {
      margin  : .5em;
      border  : 1px solid lightgrey;
      padding : .4em;
    }
    <details>
      <summary>Details1</summary>
      test1
      <details>
        <summary>Details2</summary>
        test2
        <details>
          <summary>Details3</summary>
          test3
        </details>
      </details>
    </details>