jQuery Accessible Accordion system, using ARIA

Find/fork me on Github

Other accessible plugins

The jQuery plugin will transform a simple list of hx and contents into a fantastic-shiny accordion system, using ARIA.

Here are how-to-use and some examples of this plugin.

Last updates

23th of February, 2017: fixed an issue on multi-selectable option, thanks to tonykim5.

14th of February, 2017: fixed an issue in case of nested accordions, thanks to MEDIUM-ch, and added the version number in JavaScript file, as suggested by @juliemoynat.

1st of February, 2017: added support for UMD, thanks to jules1029.

24th of October, 2016: major refactoring, thanks to the fantastic work made by Yvain Liechti).

It’s robust & accessible

It’s robust

As it relies on a normal HTML structure (a list hx and contents), even if the JavaScript isn’t loaded, your page will work, it’s the miracle of progressive enhancement.

It’s accessible

It is based on ARIA Design Pattern for accordions.

It loves keyboards

Keyboard navigation is supported too, here are the shortcuts:
(Left and Right are inverted on RTL websites)

If you focus on the accordion “buttons”:

  • use Up/Left to put focus on previous accordion button,
  • use Down/Right to put focus on next accordion button
  • use Home to put focus on first accordion button (wherever you are in accordion buttons)
  • use End to put focus on last accordion button (wherever you are in accordion buttons)

And strike space or return on an accordion button to open/close it.

If you focus on accordion content:

  • use Ctrl Up to set focus on the accordion button for the currently displayed accordion content
  • use Ctrl PageUp to set focus on the previous accordion button for the currently displayed accordion content
  • use Ctrl PageDown to set focus on the next accordion button for the currently displayed accordion content

Warning: Ctrl+PageUp/PageDown combination could activate for some browsers a switch of browser tabs. Nothing to do for this, as far as I know (if you have a solution, let me know).

It’s lightweight and free

Lightweight

Its weight is only:

  • 12kb (development, readable by humans);
  • 4.4kb (minified, readable by machines);
  • 1.3kb minified and gzipped (readable by… mutants‽‽)

Free

No license problem: it uses MIT license, so it’s free, open-source and you can do whatever you want with it, including commercial use. This permission notice shall be included in all copies or substantial portions of it.

However, it is not prohibited to tell me that you’ve used it, or send me a little “thank you”. ;)

How does it work?

Basically it will transform this:

<div class="js-accordion" data-accordion-prefix-classes="your-prefix-class">
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">First tab</h2>
   <p>Content of 1st tab</p>
 </div>
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">Second tab</h2>
   <p>Content of 2nd tab</p>
 </div>
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">Third tab</h2>
   <p>Content of 3rd tab</p>
 </div>
</div>

Into this:

<div class="your-prefix-class" 
   data-accordion-prefix-classes="your-prefix-class"
   role="tablist" aria-multiselectable="true">

 <button id="accordion1_tab1" 
     class="js-accordion__header your-prefix-class__header" 
     aria-controls="accordion1_panel1" aria-expanded="false" 
     role="tab" aria-selected="true">
       First tab
 </button>

 <div id="accordion1_panel1" 
     class="js-accordion__panel your-prefix-class__panel" 
     aria-labelledby="accordion1_tab1" 
     role="tabpanel" aria-hidden="true">

   <h2 class="your-prefix-class__title" tabindex="0">First tab</h2>
   <p>Content of 1st tab</p>

 </div>
 … etc…
</div>

The plugin will do the rest (all ids, ARIA attributes, buttons are generated on the fly).

How to use it

Just download the plugin:

jQuery accessible accordion using ARIA on Github

And use jQuery of course :)

You may also use npm command: npm i jquery-accessible-accordion-aria or bower: bower install jquery-accessible-accordion-aria

Then, follow the conventions given in this minimal example.

<div class="js-accordion" data-accordion-prefix-classes="your-prefix-class">
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">First tab</h2>
   <p>Content of 1st tab</p>
 </div>
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">Second tab</h2>
   <p>Content of 2nd tab</p>
 </div>
 <div class="js-accordion__panel">
   <h2 class="js-accordion__header">Third tab</h2>
   <p>Content of 3rd tab</p>
 </div>
</div>

The minimal style needed is:

.your-prefix-class__panel[aria-hidden=true] {
  display: none;
}

Do not forget to call the plugin:

$(function () {
   $('.js-accordion').accordion();
});

How to style it (nicely)

In this example page, I’ve used data-accordion-prefix-classes="minimalist-accordion", so all the generated classes will start with .minimalist-accordion (.minimalist-accordion__header, .minimalist-accordion__panel and .minimalist-accordion__title).

.minimalist-accordion__panel[aria-hidden=true] {
  display: none;
}

.minimalist-accordion__header {
  display: block;
}

/* title opened */
.minimalist-accordion__header[aria-expanded="true"]:before {
  content: "- ";
}
/* title closed */
.minimalist-accordion__header[aria-expanded="false"]:before {
  content: "+ ";
}

/* title selected */
.minimalist-accordion__header[aria-selected="true"]:after {
  content: " (sel)";
}
/* title non selected */
.minimalist-accordion__header[aria-selected="false"]:after {
  content: " (unselc)";
}

Bonus: wanna see it animated?

You should click on this link to activate them: Activate animations for this accordion.

What will happen? I will change the attribute data-accordion-prefix-classes="minimalist-accordion" to animated-accordion, without changing (almost) anything else to this page. Magic? No. :)

The magic is the same used for my jQuery simple and accessible hide-show system animated.

In fact, it is possible using some CSS transitions. You have to keep in mind several things to keep it accessible:

  • You can’t animate the display property, and height property might be complicated too to animate.
  • So you can’t use display: none; to hide a content (even for assistive technologies).
  • You have to set up visibility to visible or hidden to show/hide a content.
  • Basically, you should animate max-height, opacity (if needed), and use visibility to hide content to assistive technology.

So here is the CSS code (unprefixed):

.animated-accordion__panel {
 display: block;
 overflow: hidden;
 opacity: 1;
 transition: visibility 0s ease, max-height 1s ease, opacity 1s ease ;
 max-height: 100em;
 /* magic number for max-height = enough height */
 visibility: visible;
 transition-delay: 0s;
 margin: 0;
 padding: 0;
}
/* This is the hidden state */
[aria-hidden=true].animated-accordion__panel {
 display: block;
 max-height: 0;
 opacity: 0;
 visibility: hidden;
 transition-delay: 1s, 0s, 0s;
 margin: 0;
 padding: 0;
}

Here is the trick: from “hidden” to “visible” state, visibility is immediately set up to visible, and max-height/opacity are “normally” animated.

From “visible” to “hidden” state, the visibility animation is delayed. So the content will be immediately hidden… at the end of the animation of max-height/opacity.

Bonus: content opened by default, other options

Content opened by default

If you want to have an accordion content opened by default, just add the attribute data-accordion-opened="true" on a hx, example:

<h2 class="js-accordion__header" data-accordion-opened="true">
 Second tab
</h2>

And the plugin will open its content.

Other options

The ARIA Design Pattern for accordions allows to have several accordion panels opened at the same time (which is shown by the attribute aria-multiselectable="true"). However, you might need to avoid this for design purposes or client request. To do this, you may set this attribute on the accordion container: data-accordion-multiselectable="none". Example:


  <div class="js-accordion" data-accordion-multiselectable="none" …>
  

This option will set up aria-multiselectable="false" and the plugin will allow only one panel to be opened at the same time.

Older updates

7th of September, 2016: Fixed an issue in case of nested accordions (thanks to John Cheesman).

10th of April 2016: added a section for animating the accordion. You may also install this plugin using bower: bower install jquery-accessible-accordion-aria

20th of January 2016: this plugin is available on NPMjs.com

10th of July, 2015: Added option data-accordion-multiselectable="none", to avoid having several panels opened at the same time.

24th of April, 2015: Fixed a focus issue on iOS 7/8 (thanks to @goetsu). Fixed a “vocal” issue on example (thanks to @cahnory and @ffoodd_fr).