nico3333fr / jquery-accessible-accordion-aria

jQuery Accessible Accordion System, using ARIA
MIT License
60 stars 19 forks source link

Is there a way to open/close all panels at once? #34

Open bendur opened 5 years ago

bendur commented 5 years ago

It would be nice to have an open/close all method to act on everything in the accordion at once.

LordPachelbel commented 5 years ago

I wrote some code to do this a while back. You can see a working example at https://ssbhibbing.com/faq.html

HTML

<div class="js-accordion">

  <!-- add this button to the accordion parent/wrapper element -->
  <button type="button" class="expand-collapse" aria-pressed="false">
    <span class="expand">Expand all</span>
    <span class="collapse">Collapse all</span>
  </button>

  <div class="js-accordion__panel">
    <h2 class="js-accordion__header">First tab</h2>
    <p>here is the content of the 1st tab</p>   
 </div>

  // and so on …

</div>

jQuery

$('.expand-collapse').click(function(e) {
  e.preventDefault();

  // toggle this button's ARIA attribute and a status variable we'll use to only expand and collapse stuff that isn't already expanded or collapsed
  var expandedStateToggle = 'false';
  if($(this).attr('aria-pressed') === 'false') {  // button is in the "off" state, so we're going to expand the accordions
    $(this).attr('aria-pressed', 'true');
    expandedStateToggle = 'false';
  } else {                    // button is in the "on" state, so we're going to collapse the accordions
    $(this).attr('aria-pressed', 'false');
    expandedStateToggle = 'true';
  }

  // set up an event handler that will return focus to the Expand/Collapse button after we expand/collapse all of the accordion panels (because the accordion plugin leaves the focus on whichever accordion heading button was clicked, and we're about to click all of them at once)
  // the .one() function is not a misspelled .on() function -- .one() fires only once
  // (code based on http://blog.teamtreehouse.com/using-jquery-to-detect-when-css3-animations-and-transitions-end)
  $(this)
    .siblings('.js-accordion__panel')
    .one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function() {
    // NOTE: inside this event handler, $(this) refers to the panel element[s] that fired this event, so we have to use e.target to refer to the Expand/Collapse button

    //console.log('transitions are done');

    e.target.focus(); // return the focus to the Expand/Collapse button
    });

  // trigger the accordion heading buttons' click events to expand/collapse their associated panels, but only the ones that aren't already affected
  $(this).siblings('.js-accordion__header[aria-expanded="' + expandedStateToggle + '"]').click();

  // scroll the page back to Expand/Collapse button
  $([document.documentElement, document.body]).animate({
    scrollTop: $(this).offset().top - 15
  }, 500);
});

Notes

Multiple Buttons Per Set of Accordions

The code is written with the assumption that there will be only one expand/collapse button within the .js-accordion parent/wrapper. If you want to have two or more buttons, e.g. one at the top of the accordions and one at the bottom, then the code will need to be changed to keep buttons' states in sync. The way it's currently written, clicking the top button will expand all of the accordions, and the bottom button will still say Expand All, and if you click that second button nothing will happen except the page will scroll a bit and the text will change to say Collapse All, and then a second click on that button will collapse all of the accordions, but the top button will still say Collapse All … and I'm sure you understand the problem.

Multiple Sets of Accordions

However, the above code can handle the situation where there are multiple .js-accordion sections on the page, because it's targeting sibling elements of the button to expand/collapse.

Minor Simplification

The part of the code that handles the ARIA attributes could perhaps be simplified by using https://github.com/marcus-herrmann/toggleAria but I haven't gotten around to that yet.