Giter Site home page Giter Site logo

van11y-accessible-accordion-aria's Introduction

Van11y ES2015 accessible accordion system, using ARIA

Van11y

This script will transform a simple list of Hx/contents into shiny and accessible accordion, using ARIA.

The demo is here: https://van11y.net/downloads/accordion/demo/index.html

Website is here: https://van11y.net/accessible-accordion/

La page existe aussi en français : https://van11y.net/fr/accordeon-accessible/

How it works

Basically it will transform this:

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

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

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

   <p>Content of 1st tab</p>

 </div>
 … etc…
</div>

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

The script is launched when the page is loaded. If you need to execute it on AJAX-inserted content, you may use for example on <div id="newContent">your accordion source</div>:

var my_accordion = van11yAccessibleAccordionAria();
my_accordion.attach(document.getElementById('newContent'));

How to use it

You may use npm command: npm i van11y-accessible-accordion-aria.

You may also use bower: bower install van11y-accessible-accordion-aria.

Then, follow the conventions given in this minimal example.

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

The minimal style needed is:

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

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)";
}

Keyboard shortcuts

Keyboard navigation is supported too, here are the shortcuts:

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.

Bonuses

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 script will open its content.

Nested accordions and cooler selectors

By default, the script supports nested accordions (since 2.1.0 version). To do this, the script is going to search for direct children of js-accordion. However, it is possible to activate a less strict mode if your site requires some div between js-accordion and js-accordion__header, this can be achieved using data-accordion-cool-selectors="1" attribute, to put onto js-accordion element. The first demo illustrates this feature.

Default config

const CONFIG = {
    ACCORDION_JS: 'js-accordion',
    ACCORDION_JS_HEADER: 'js-accordion__header',
    ACCORDION_JS_PANEL: 'js-accordion__panel',

    ACCORDION_DATA_PREFIX_CLASS: 'data-accordion-prefix-classes',
    ACCORDION_DATA_OPENED: 'data-accordion-opened',
    ACCORDION_DATA_MULTISELECTABLE: 'data-accordion-multiselectable',
    ACCORDION_DATA_COOL_SELECTORS: 'data-accordion-cool-selectors',

    ACCORDION_PREFIX_IDS: 'accordion',
    ACCORDION_BUTTON_ID: '_tab',
    ACCORDION_PANEL_ID: '_panel',

    ACCORDION_STYLE: 'accordion',
    ACCORDION_TITLE_STYLE: 'accordion__title',
    ACCORDION_HEADER_STYLE: 'accordion__header',
    ACCORDION_PANEL_STYLE: 'accordion__panel',

    ACCORDION_ROLE_TABLIST: 'tablist',
    ACCORDION_ROLE_TAB: 'tab',
    ACCORDION_ROLE_TABPANEL: 'tabpanel',

    ATTR_ROLE: 'role',
    ATTR_MULTISELECTABLE: 'aria-multiselectable',
    ATTR_EXPANDED: 'aria-expanded',
    ATTR_LABELLEDBY: 'aria-labelledby',
    ATTR_HIDDEN: 'aria-hidden',
    ATTR_CONTROLS: 'aria-controls',
    ATTR_SELECTED: 'aria-selected',
    ...config
};

If you need to use another configuration, you may call the plugin like this:

var other_accordion = van11yAccessibleAccordionAria({
    ACCORDION_PREFIX_IDS: 'peekaboo_',
    ACCORDION_JS: 'js-accordion2'
});
other_accordion.attach();

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 script will allow only one panel to be opened at the same time.

van11y-accessible-accordion-aria's People

Contributors

nico3333fr avatar spone avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

van11y-accessible-accordion-aria's Issues

Tablist Role Nesting

Greetings. Would it be possible to check on these issues?

  • Hidden element has focusable content
  • Role not inside the required context
  • Container element is empty

Using the updated Siteimprove accessibility checker plugin for Chrome these A level issues are shown on the demo page.

  • Hidden element has focusable content is shown on the tab panel "Not opened by default" as it includes aria-hidden is true but the included paragraph has a span with tab index of zero indicating a focusable element.

  • Role not inside the required context is shown on the button tag with role="tab." I believe the tab role containers needs to immediately follow the container with role="tablist".

  • Container element is empty is shown on the divisions with role tablist. I believe the tablist role container needs to immediately precede the containers with role="tab".

Thanks

Combine tabs and accordion

Hi, first of all I would like to thank you for this 'a11y' - treasures. This plugins looks wonderful!

I have a question. Is there a way to combine your tabs and accordion plugins into one? I need to create an ARIA ready tabs panel which transforms into accordion on smaller screens.

Invoke programmatically

Hey!

Nice accordion.
I'm using this on a project where I have transitions from page to page via pjax.
Thus I need to be able to initialize accordions when a page is fetched.

Any idea on how I can achieve this?

Generated numerical ID invalid selector

I run into a problem where any ID for an accordion that starts with a number, like id="6rjsaq98q2" breaks when used.

Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#6rjsaq98q2[data-hashaccordion-id="k0vuv1jup0"]' is not a valid selector.

No problem when generated ID starts with a letter.

document.body is null when loading

When loading the script in the head section, it doesn't work, because document.body is null here (line 269):

var main = function main() {

    /* listeners for all configs */
    ['click', 'keydown', 'focus'].forEach(function (eventName) {

        document.body.addEventListener(eventName, function (e) {

This happens because the main method is called as soon as the script is loaded and not the DOMContentLoaded handler. No DOM access should be attempted before DOMContentLoaded. I just changed it to be document.addEventListener directly, which works fine. But maybe some of that code should be moved to the DOMContentLoaded handler instead?

Open All and Close All?

Hi, how would you implement a Show (or Open) All and Close All functionality with this library?

Thanks!

Event method hooks?

First off, thanks for this great plugin. It's nice to find a high quality accessible component plugin without a jQuery dependency.

One feature I'd like to suggest adding is some event method hooks so the plugin can be easily extended. Some basic events I was thinking would be useful are:

  • on initialization
  • on collapse
  • on expand

The expand/collapse ones could even be more granular with separate before/after methods.

Class name inconsistency js-accordion__header [potential bug]

The js-accordion__header class starts on the <hx> element but when JavaScript takes over the element is given js-accordion__title and the child <button> is given js-accordion__header. E.g:

h2.js-accordion__header

Becomes

h2.js-accordion__title.custom-accordion__title
  button.js-accordion__header.custom-accordion__header

I require both non/javascript versions to have the same style so I applied custom-accordion__header to my source HTML. This causes style problems because custom-accordion__header ends up being nested inside itself. Like so:

h2.js-accordion__title.custom-accordion__header
  button.js-accordion__header.custom-accordion__header

I did try changing the classes generated with:

var other_accordion = van11yAccessibleAccordionAria({
    ACCORDION_HEADER_STYLE: 'accordion__button'
});
other_accordion.attach();

This solved the style problem, but broke the toggle functionality. The following was logged to the console.

"Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#[data-hashaccordion-id="otef8le46q"]' is not a valid selector."

In the end, I have had to drop the use of custom prefixes and only use js-accordion__xxx which isn't the end of the world.

Possible solution to this problem
Have the heading element keep js_accordion__header and the generated button be given a class of js-accordion__button

Nested accordions

Hello, I'm back! 😉

While using your great accordion I came across a use case where I want to have multiple accordions within another accordion. I set this up and ran into trouble, namely:
Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.

Is this something you'd able to look into?

Cheers, and thanks for this awesome accordion again!

Scroll when open

Hello:

First: thank you very much for this great piece of software and for your work!

Just a question: Is it possible to scroll the page to read better the panel when accordion parent is opened?

I mean, when I click on the parent's button, scroll the page to see on top the title and then panel content.

Thank you and best regards

after giving js file reference, build is getting failed

Hi, I am using your accessible accordions, however my MVN build is getting failed every time , I am giving your JS file reference. Please see below, what I am doing:

  1. A JSP page where I am using accordion
  2. Gave your js file reference in JSP page and I have added JS file in that location

And then I am building my app using MVN CLEAN INSTALL command and it is getting failed.

"Uncaught DOMException: Failed to execute 'querySelector'" error

Hi,
I am using the latest version (3.0) of this accessible accordion and there is apparently an issue with the data-hashaccordion-id. When I click on the accordion, sometimes the accordion won't open and the console throws the following error:

Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#86gigjp0th[data-hashaccordion-id="lhcov0q06c"]' is not a valid selector.

I ran into this error in my project as well as on the demo page.

Steps to reproduce:

On the demo page, click on the first accordion (on any of the headers).
If the accordion opens properly, refresh the page and try again.

Is it possible to fix this?
Thank you in advance

Question about tabs and accordion

Hi @nico3333fr,

First, thank you for the huge amount of work a high quality library and example you provide.
I need to implement Tabs but with a behaviour trick: the current panel needs to be togglable by clicking on the related tab button.
As far as I understand there is no "accordion role", it looks like Tabs component with more options.

Accordion is similar to TabList:

  • it uses tablist/tab/tabpanel roles
  • it has the keyboard arrows behavior

Accordion differs from Tablist:

  • it is not using tab roving
  • it adds aria-multiselectable to the tablist element
  • it adds aria-expanded to the tab element

My usecase is a bit weird I know, so I'll probably write my own solution inspired by your great library but I'd like to know your advice.

Do you think using a Tab component and add aria-expanded, aria-multiselectable="false" and implement a custom development to be able to toogle the Tab is the right way to go?

Regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.