Robuste et accessible

  • Comme c’est basé sur une structure HTML de base (Hx et contenus), même si le JavaScript n’est pas chargé, la page marchera, c’est le miracle de l’amélioration progressive ;
  • C’est basé sur le Design Pattern ARIA pour les accordéons ;
  • Pas de CSS/JavaScript injecté en ligne, le DOM reste propre, ce qui cool pour le responsive.

C’est (hautement) personnalisable

  • Vous pouvez le styler comme vous voulez ;
  • Vous pouvez utiliser des transitions ou animations… comme vous voulez ;
  • Vous pouvez créer un namespace pour les classes générées si vous avez besoin de différents comportements dans la même page ;
  • Chaque aspect du script peut être personnalisé, la configuration par défaut peut être surchargée à l’appel du plugin, si vous transpilez le script en ES5, ce sera compatible IE9+.

Libre et sous une license permissive

  • Pas de problème : c’est placé sous licence MIT, donc c’est libre, open-source et vous pouvez faire ce que vous voulez avec, incluant une utilisation commerciale. Cette note de permission doit être incluse dans toutes les copies complètes ou partielles du script.
  • Cependant, il n’est pas interdit de me dire que vous l’avez utilisé, ou de m’envoyer un petit « merci ». ;)

Léger

  • 20kb (développement, lisible par les humains) ;
  • ~8kb (minifié, lisible par des machines) ;
  • ~2,8kb minifié et gzippé (lisible par… des mutants ‽‽)

Comment ça marche

Simplement, cela va transformer ceci :

<div class="js-accordion" data-accordion-prefix-classes="your-prefix-class">
 <h2 class="js-accordion__header">Premier élément</h2>
 <div class="js-accordion__panel">
   <p>Contenu du premier élément</p>
 </div>
 <h2 class="js-accordion__header">Deuxième élément</h2>
 <div class="js-accordion__panel">
   <p>Contenu du deuxième élément</p>
 </div>
 <h2 class="js-accordion__header">Troisième élément</h2>
 <div class="js-accordion__panel">
   <p>Contenu du troisième élément</p>
 </div>
</div>

En ceci :

<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-accordion__header" 
     aria-controls="accordion1_panel1" aria-expanded="false" 
     role="tab" aria-selected="true" type="button">
       Premier élément
 </button>
 </h2>

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

   <p>Contenu du premier élément</p>

 </div>
 … etc…
</div>

Le script fera tout le boulot (les ids, les attributs ARIA, les buttons sont générés à la volée).

Le script est lancé au chargement de la page. Si vous avez besoin de l’exécuter sur du contenu généré en AJAX, vous pourrez utiliser par exemple sur <div id="newContent">la source de l’accordéon</div> :

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

Comment l’utiliser

Vous pouvez utilisez la commande npm : npm i van11y-accessible-accordion-aria.
Vous pouvez aussi utiliser Bower : bower install van11y-accessible-accordion-aria.

Ensuite, il faut suivre les conventions données dans cet exemple minimaliste.

<div class="js-accordion" data-accordion-prefix-classes="your-prefix-class">
 <h2 class="js-accordion__header">Premier élément</h2>
 <div class="js-accordion__panel">
   <p>Content of 1st tab</p>
 </div>
 <h2 class="js-accordion__header">Deuxième élément</h2>
 <div class="js-accordion__panel">
   <p>Content of 2nd tab</p>
 </div>
 <h2 class="js-accordion__header">Troisième élément</h2>
 <div class="js-accordion__panel">
   <p>Content of 3rd tab</p>
 </div>
</div>

Le style minimum nécessaire est le suivant :

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

Comment (bien) le styler

Dans cette page d’exemple, j’ai utilisé data-accordion-prefix-classes="minimalist", donc toutes les classes générées commenceront par .minimalist-accordion (.minimalist-accordion__header, .minimalist-accordion__panel et .minimalist-accordion__title).

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

.minimalist-accordion__header {
  display: block;
}

/* titre ouvert */
.minimalist-accordion__header[aria-expanded="true"]:before {
  content: "- ";
}
/* titre fermé */
.minimalist-accordion__header[aria-expanded="false"]:before {
  content: "+ ";
}

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

Configuration par défaut

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

Si vous avez besoin d’une autre configuration, il faut appeler le plugin ainsi :

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

Et tout fonctionnera comme vous le souhaitez.

Raccourcis clavier

La navigation au clavier est également supportée, voici les raccourcis :

Si le focus est sur les « boutons » de l’accordéon :

  • utilisez Haut/Gauche pour mettre le focus sur le bouton précédent de l’accordéon,
  • utilisez Bas/Droite pour mettre le focus sur le bouton suivant de l’accordéon
  • utilisez Home pour mettre le focus sur le premier bouton de l’accordéon (où qu’on soit sur les boutons de l’accordéon)
  • utilisez End pour mettre le focus sur le dernier bouton de l’accordéon (où qu’on soit sur les boutons de l’accordéon)

Et appuyez sur espace ou entrée sur un bouton de l’accordéon pour les ouvrir/fermer.

Bonus

Contenu ouvert par défaut

Si vous voulez qu’un contenu de l’accordéon soit ouvert par défaut, ajoutez l’attribut data-accordion-opened="true" sur un hx, exemple :

<h2 class="js-accordion__header" data-accordion-opened="true">
 Deuxième élément
</h2>

Et le script fera que le contenu soit ouvert.

Accordéons imbriqués et sélecteurs plus cools

Par défaut, le script supporte les accordéons imbriqués (depuis la version 2.1.0). Pour ce faire, le script va chercher les enfants directs de js-accordion. Toutefois, il est possible d’activer un mode moins strict si votre intégration doit avoir des div entre js-accordion et js-accordion__header, cela peut se faire avec l’attribut data-accordion-cool-selectors="1" à poser sur js-accordion. La première démo illustre cette possibilité.

Autre options

Le design pattern ARIA pour les accordéons autorise d’avoir plusieurs panels ouvert en même temps (ce qui est indiqué par l’attribut aria-multiselectable="true"). Cependant, vous pouvez avoir besoin d’éviter ce comportement. Pour ce faire, vous pouvez spécifier l’attribut sur le conteneur de l’accordéon : data-accordion-multiselectable="none". Exemple :

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

Cette option ajouter l’attribut aria-multiselectable="false" et le script n’autorisera qu’un seul contenu ouvert en même temps.