Robuste et accessible

  • Comme c’est basé sur une structure HTML de base (Hx), même si le JavaScript n’est pas chargé, la page marchera, c’est le miracle de l’amélioration progressive ;
  • La navigation au clavier est fournie avec, inspirée par le Design Pattern ARIA des panneaux dépliants, vous pouvez les activer avec Entrée ou Espace ;
  • 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 des 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

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

Comment ça marche

Simplement, cela va transformer ceci :

<h2 class="js-expandmore">Lorem dolor si amet</h2>
<div class="js-to_expand">
   Ici le contenu caché
</div>

En ceci :

<h2 class="js-expandmore">
  <button aria-controls="expand_1" aria-expanded="false" class="expandmore__button">
   <span class="expandmore__symbol" aria-hidden="true"></span>
   Lorem dolor si amet
  </button>
</h2>
<div id="expand_1" class="js-to_expand" aria-labelledby="label_expand_1">
   Ici le contenu caché
</div>

Les attributs et leurs valeurs sont générés à la volée (data-controls="expand_1", id="expand_1", data-labelledby="label_expand_1"), pas besoin de vous en soucier

Comment l’utiliser

Téléchargez le script

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

Conventions

Ensuite, suivez cette convention (qui peut être adaptée selon vos besoins, voir « Configuration par défaut ») :

<h2 class="js-expandmore">Lorem dolor si amet</h2>
<div class="js-to_expand">
   Ici le contenu caché
</div>

Pour des raisons d’accessibilité, vous devez poser la classe class="js-expandmore" sur un élément Hx (h1, h2, h3, etc.).
Les éléments qui ont les classes js-expandmore et js-to_expand doivent être adjacents.

Ensuite, utilisez le script qui fera le reste.

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 des panneaux dépliants</div> :

var my_expand = van11yAccessibleHideShowAria();
my_expand.attach(document.getElementById('newContent'));

Styles nécessaires pour que cela marche

Le style minimum nécessaire est :

.js-to_expand[aria-hidden=true],
.js-to_expand[data-hidden=true] {
  display: none;
}

Cependant, comme le script ajoute un button dans le Hx, vous devrez styler cet élément. Voici un exemple :

.expandmore__button {
  background: none;
  font-size: inherit;
  color: inherit;
}
/* optionnel */
.expandmore__symbol::before {
  content : '+ ';
}
.expandmore__button[aria-expanded=true] > .expandmore__symbol::before {
  content : '− ';
}

Logique des classes pour styler

Comment créer différents styles dans la même page ?

C’est possible et même très simple, utilisez l’attribut data-hideshow-prefix-class="<votre_valeur>" comme ceci :

<h2 class="js-expandmore" data-hideshow-prefix-class="mini-combo">Lorem dolor si amet</h2>
<div class="js-to_expand">
   Ici le contenu caché
</div>

Cela préfixera les classes générées, <votre_valeur>-expandmore__button et <votre_valeur>-expandmore__to_expand, comme suit :

<h2 class="js-expandmore" data-hideshow-prefix-class="mini-combo">
 <button id="label_expand_2" class="mini-combo-expandmore__button js-expandmore-button" data-controls="expand_2" aria-expanded="false" type="button">
  Lorem dolor si amet
 </button>
</h2>
<div id="expand_2" class="js-to_expand mini-combo-expandmore__to_expand" data-hidden="true" data-labelledby="label_expand_2">
 Ici le contenu caché
</div>

Le script va préfixer toutes les classes, et donc vous pourrez les styler comme bon vous semble. Si vous n’utilisez pas cet attribut, le script n’y verra aucun problème.

Configuration par défaut

const CONFIG = {
    HIDESHOW_EXPAND: 'js-expandmore',
    HIDESHOW_BUTTON_EXPAND: 'js-expandmore-button',
    HIDESHOW_BUTTON_EXPAND_STYLE: 'expandmore__button',
    HIDESHOW_BUTTON_LABEL_ID: 'label_expand_',

    DATA_PREFIX_CLASS: 'data-hideshow-prefix-class',

    HIDESHOW_BUTTON_EMPTY_ELEMENT_SYMBOL: 'expandmore__symbol',
    HIDESHOW_BUTTON_EMPTY_ELEMENT_TAG: 'span',
    ATTR_HIDESHOW_BUTTON_EMPTY_ELEMENT: 'aria-hidden',

    HIDESHOW_TO_EXPAND_ID: 'expand_',
    HIDESHOW_TO_EXPAND_STYLE: 'expandmore__to_expand',

    /*
     recommandé par les experts a11y
    */
    ATTR_CONTROL: 'data-controls',
    ATTR_EXPANDED: 'aria-expanded',
    ATTR_LABELLEDBY: 'data-labelledby',
    ATTR_HIDDEN: 'data-hidden',

    IS_OPENED_CLASS: 'is-opened',

    DISPLAY_FIRST_LOAD: 'js-first_load',
    DISPLAY_FIRST_LOAD_DELAY: '1500',
    ...config
};

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

var other_expand = van11yAccessibleHideShowAria({
     HIDESHOW_EXPAND: 'js-expandmore2',
     DATA_PREFIX_CLASS: 'data-hideshow-prefix-class2'
    });
other_expand.attach();

Et tout fonctionnera comme vous le souhaitez.

Bonus

Ouvert par défaut

Pas de souci, c’est possible et même très simple, utilisez la classe is-opened sur :

<h2 class="js-expandmore">Lorem dolor si amet</h2>
<div class="js-to_expand is-opened">
   Ici le contenu caché
</div>

Le script va le détecter, et faire que cela soit ouvert par défaut. Aussi simple qu’un copier/coller.

Animations

Pas de souci, c’est possible en utilisant des transitions CSS. Vous devez avoir à l’esprit plusieurs choses pour faire que cela soit accessible :

  • Vous ne pouvez pas animer la propriété display, et la propriété height peut être très compliquée à animer également (sans hauteur connue).
  • Donc dans ce cas, il est impossible d’utiliser display: none; pour cacher un contenu (même pour les technologies d’assistance).
  • Donc vous devez passer la propriété visibility à visible ou hidden pour afficher/cacher un contenu.
  • En clair, vous devez animer max-height, opacity (si besoin), et utiliser visibility pour cacher le contenu aux technologies d’assistance.

Si vous avez cliqué sur cette section, vous aurez pu voir l’animation en action. Partons de l’idée qu’on a cette source :

<h2 class="js-expandmore mb0 mt0" data-hideshow-prefix-class="animated">Bonus : des animations ?</h2>
 <div class="js-to_expand"></div>

Voici donc le code CSS pour les transitions (non préfixé) :

/* Ceci est l’état ouvert */
.animated-expandmore__to_expand {
 display: block;
 overflow: hidden;
 opacity: 1;
 transition: visibility 0s ease, max-height 2s ease, opacity 2s ease ;
 max-height: 80em;
 /* nombre magique pour max-height = assez de hauteur */
 visibility: visible;
 transition-delay: 0s;
}
/* Ceci est l’état fermé */
[data-hidden=true].animated-expandmore__to_expand {
 display: block;
 max-height: 0;
 opacity: 0;
 visibility: hidden;
 transition-delay: 2s, 0s, 0s;
}

Voici l’astuce : de l’état « fermé » à l’état « ouvert », la propriété visibility est immédiatement mise à visible, et max-height/opacity sont « normalement » animées.

De l’état « ouvert » à l’état « fermé », l’animation de la propriété visibility a un délai. Donc le contenu sera caché… à la fin de l’animation de max-height/opacity.

Attributs ARIA ou attributs data ?

Pas de souci. Au début du code du script, voici la configuration par défaut :

ATTR_CONTROL: 'data-controls',
ATTR_EXPANDED: 'aria-expanded',
ATTR_LABELLEDBY: 'data-labelledby',
ATTR_HIDDEN: 'data-hidden',

Cette configuration par défaut est recommandée par les experts accessibilité (et pour fonctionner dans le plus de cas possibles).

Si vous avez besoin de faire autrement, vous pouvez, le script s’adaptera. Exemple :

var my_expand = van11yAccessibleHideShowAria({
    ATTR_CONTROL: 'aria-controls',
    ATTR_EXPANDED: 'aria-expanded',
    ATTR_LABELLEDBY: 'aria-labelledby',
    ATTR_HIDDEN: 'aria-hidden',
    });
my_expand.attach();

Bien sûr, il faudra mettre à jour votre CSS en utilisant les bons attributs si besoin est.