Panneaux d'onglets accessibles, compatibles Search Engine Optimization, mobile et desktop
Construction d'un système de panneaux d'onglets permettant la navigation au clavier (accessibilité Web Accessibility Initiative-Accessible Rich Internet Applications) compatible terminaux mobiles et Search Engine Optimization
Construction d'un système d'onglets/panneaux (tab panel) permettant la navigation au clavier. En cas d'un nombre important d'onglets, le script permet de gérer le déplacement de la prise de focus.
L'activation des panneaux est automatique au focus ou clic sur les onglets.
Interaction clavier
- Touche clavier Touche clavier Flèche vers la droite → : si le focus est sur un onglet, déplace le focus vers l'onglet suivant. Si le focus est sur le dernier onglet, déplace le focus vers le premier onglet ;
- Touche clavier Touche clavier Flèche vers la gauche ← : si le focus est sur un onglet, déplace le focus vers l'onglet précédent. Si le focus est sur le premier onglet, déplace le focus vers le dernier onglet ;
- Touche clavier Touche clavier Tabulation ⇥ : déplace le focus vers l’élément focalisable suivant; tous les éléments focusables du panneau affiché sont inclus dans la séquence de page ;
- Touche clavier Touche clavier Majuscule ⇧ Touche clavier Tabulation ⇥ : déplace le focus vers l’élément focusable précédent; tous les éléments focusables du panneau affiché sont inclus dans la séquence de page.
Et le Search Engine Optimization ?
Les moteurs de recherche doivent pouvoir « lire » le contenu des panneaux qui ne sont pas affichés.
Il faut donc éviter de dissimuler complètement ces panneaux et gérer l'affichage en effectuant un « clip »
des éléments.
Le markup strictement nécessaire
<!-- 
 Le container global 
 Pour activer un panneau autre que le premier, ajouter l'attribut 
 data-init-tab="5" par exemple
-->
 
 <div class="tabs-panels" id="uniq-id-panel">
 
 <!-- Les onglets -->
 <div role="tablist" aria-label="Système d'onglets">
 <button role="tab"
 type="button"
 id="tab-button-1"
 aria-controls="panel-1">Onglet 1</button>
 <button role="tab"
 type="button"
 id="tab-button-2"
 aria-controls="panel-2">Onglet 2</button>
 <!-- ajouter autant d'onglets que nécessaire -->
 </div>
 <!--./ fermeture des onglets -->
 
 <!-- Les panneaux -->
 <div role="tabpanel" id="panel-1"
 aria-labelledby="tab-button-1">
 <!-- CONTENU DU PANNEAU… -->
 </div>
 <div role="tabpanel" id="panel-2"
 aria-labelledby="tab-button-2">
 <!-- CONTENU DU PANNEAU… -->
 </div>
 
 <!-- 
 ajouter autant de panneaux que nécessaire 
 en prenant soin de gérer les relations ID/aria-describedby 
 -->
 
 </div>
Exemples d'onglets accessibles
Exemple #1
Onglets sans présélection active (1er élément actif) et affichage automatique du panneau au clic ou au focus en navigation clavier avec les flèches droite et gauche.
L'affichage automatique du panneau est géré par l'ajout d'un attribut data-auto-display sur le conteneur tab-panels.
2 août 2026, 08h43
Sur(é)veillé.
22 juillet 2026, 13h07
— Google, trouve-moi une station service pour faire le plein.
— Trouvée !
— Ok, merci…
Espagne, juillet 2026.
21 juillet 2026, 13h53
Family holidays, les FOMO.
23 juin 2026, 20h48
2 mars 2026, 09h28
Paris, boulevard de Vaugirard.
L'amour, l'amour, l'amour Bon Entendeur - Mouloudji
3 juillet 2025, 08h35
Communiquer : XIVème siècle, au sens de « participer à quelque chose ». Emprunté du latin communicare, « mettre en commun, communiquer », puis « être en relation avec ».
Bordeaux, 27 juillet 2012, 18h31
Bordeaux Lac, 10 août 2022, 19h33
Bordeaux plage.
Code du bloc
<section data-auto-display class="tabs-panels" id="section-panel-1" data-skip='{"label":"Passer les onglets", "after":"Revenir avant les onglets"}'>
 <div role="tablist" aria-label="Exemple de tabpanel"> 
 <button role="tab" type="button" id="tab-1-1" aria-controls="panel-1-1">
 2 août 2026, 08h43
 </button>
 <button role="tab" type="button" id="tab-1-2" aria-controls="panel-1-2">
 22 juillet 2026, 13h07
 </button>
 <button role="tab" type="button" id="tab-1-3" aria-controls="panel-1-3">
 21 juillet 2026, 13h53
 </button>
 <button role="tab" type="button" id="tab-1-4" aria-controls="panel-1-4">
 23 juin 2026, 20h48
 </button>
 <button role="tab" type="button" id="tab-1-5" aria-controls="panel-1-5">
 2 mars 2026, 09h28
 </button>
 <button role="tab" type="button" id="tab-1-6" aria-controls="panel-1-6">
 3 juillet 2025, 08h35
 </button>
 <button role="tab" type="button" id="tab-1-7" aria-controls="panel-1-7">
 Bordeaux, 27 juillet 2012, 18h31
 </button>
 <button role="tab" type="button" id="tab-1-8" aria-controls="panel-1-8">
 Bordeaux Lac, 10 août 2022, 19h33
 </button>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-1" aria-labelledby="tab-1-1">
 <h4 class="h2">2 août 2026, 08h43</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/2-aout-2026-08h43.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/2-aout-2026-08h43.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/2-aout-2026-08h43.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 2 août 2026, 08h43</span>
 </a>
 </div>
 <div class="s-12 markdown"><p>Sur(é)veillé.</p></div>
 </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-2" aria-labelledby="tab-1-2">
 <h4 class="h2">22 juillet 2026, 13h07</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/22-juillet-2026-13h07.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/22-juillet-2026-13h07.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/22-juillet-2026-13h07.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 22 juillet 2026, 13h07</span>
 </a>
 </div>
 <div class="s-12 markdown"><p>— Google, trouve-moi une station service pour faire le plein.<br >
— Trouvée !<br >
— Ok, merci…<br >
Espagne, juillet 2026.</p></div>
 </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-3" aria-labelledby="tab-1-3">
 <h4 class="h2">21 juillet 2026, 13h53</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/21-juillet-2026-13h53.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/21-juillet-2026-13h53.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/21-juillet-2026-13h53.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 21 juillet 2026, 13h53</span>
 </a>
 </div>
 <div class="s-12 markdown"><p>Family holidays, les FOMO.</p></div>
 </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-4" aria-labelledby="tab-1-4">
 <h4 class="h2">23 juin 2026, 20h48</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/23-juin-2026-20h48.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/23-juin-2026-20h48.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/23-juin-2026-20h48.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 23 juin 2026, 20h48</span>
 </a>
 </div> </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-5" aria-labelledby="tab-1-5">
 <h4 class="h2">2 mars 2026, 09h28</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/2-mars-2026-09h28.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/2-mars-2026-09h28.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/2-mars-2026-09h28.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 2 mars 2026, 09h28</span>
 </a>
 </div>
 <div class="s-12 markdown"><p>Paris, boulevard de Vaugirard.<br >
<a href="https://link.deezer.com/s/32C1OF9p8U0qBcBqZQ4a4" class="blank">L'amour, l'amour, l'amour</a> Bon Entendeur - Mouloudji</p></div>
 </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-6" aria-labelledby="tab-1-6">
 <h4 class="h2">3 juillet 2025, 08h35</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/3-juillet-2025-08h35.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/3-juillet-2025-08h35.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/3-juillet-2025-08h35.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 3 juillet 2025, 08h35</span>
 </a>
 </div>
 <div class="s-12 markdown"><p><strong>Communiquer</strong> : XIV<sup>ème</sup> siècle, au sens de « participer à quelque chose ». Emprunté du latin communicare, « mettre en commun, communiquer », puis « être en relation avec ».</p></div>
 </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-7" aria-labelledby="tab-1-7">
 <h4 class="h2">Bordeaux, 27 juillet 2012, 18h31</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/bordeaux-27-juillet-2012-18h31.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/bordeaux-27-juillet-2012-18h31.jpg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/bordeaux-27-juillet-2012-18h31.jpg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo Bordeaux, 27 juillet 2012, 18h31</span>
 </a>
 </div> </div>
 </div>
<div role="tabpanel" class="outer-line" id="panel-1-8" aria-labelledby="tab-1-8">
 <h4 class="h2">Bordeaux Lac, 10 août 2022, 19h33</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/bordeaux-lac-10-aout-2022-19h33.html" class="ratio-100">
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/bordeaux-lac-10-aout-2022-19h33.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/bordeaux-lac-10-aout-2022-19h33.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo Bordeaux Lac, 10 août 2022, 19h33</span>
 </a>
 </div>
 <div class="s-12 markdown"><p>Bordeaux plage.</p></div>
 </div>
 </div>
</section>Exemple #2
Onglets avec présélection du deuxième élément.
L'affichage du panneau n'est pas automatique en navigation au clavier. Appuyer sur Touche clavier Entrée ↲ ou Touche clavier Barre d'espace Espace pour activer l'affichage du panneau correspondant.
2 août 2026, 08h43
Sur(é)veillé.
22 juillet 2026, 13h07
— Google, trouve-moi une station service pour faire le plein.
— Trouvée !
— Ok, merci…
Espagne, juillet 2026.
21 juillet 2026, 13h53
Family holidays, les FOMO.
23 juin 2026, 20h48
2 mars 2026, 09h28
Paris, boulevard de Vaugirard.
L'amour, l'amour, l'amour Bon Entendeur - Mouloudji
3 juillet 2025, 08h35
Communiquer : XIVème siècle, au sens de « participer à quelque chose ». Emprunté du latin communicare, « mettre en commun, communiquer », puis « être en relation avec ».
Bordeaux, 27 juillet 2012, 18h31
Bordeaux Lac, 10 août 2022, 19h33
Bordeaux plage.
Code du bloc
<section data-init-tab="1" class="tabs-panels" id="section-panel-2" data-skip='{"label":"Passer les onglets", "after":"Revenir avant les onglets"}'>
 <div role="tablist" aria-label="Exemple de tabpanel">
 <button role="tab" type="button" id="tab-2-1" aria-controls="panel-2-1">
 2 août 2026, 08h43
 </button>
 <button role="tab" type="button" id="tab-2-2" aria-controls="panel-2-2">
 22 juillet 2026, 13h07
 </button>
 <button role="tab" type="button" id="tab-2-3" aria-controls="panel-2-3">
 21 juillet 2026, 13h53
 </button>
 <button role="tab" type="button" id="tab-2-4" aria-controls="panel-2-4">
 23 juin 2026, 20h48
 </button>
 <button role="tab" type="button" id="tab-2-5" aria-controls="panel-2-5">
 2 mars 2026, 09h28
 </button>
 <button role="tab" type="button" id="tab-2-6" aria-controls="panel-2-6">
 3 juillet 2025, 08h35
 </button>
 <button role="tab" type="button" id="tab-2-7" aria-controls="panel-2-7">
 Bordeaux, 27 juillet 2012, 18h31
 </button>
 <button role="tab" type="button" id="tab-2-8" aria-controls="panel-2-8">
 Bordeaux Lac, 10 août 2022, 19h33
 </button>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-1" aria-labelledby="tab-2-1">
 <h4 class="h2">2 août 2026, 08h43</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/2-aout-2026-08h43.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/2-aout-2026-08h43.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/2-aout-2026-08h43.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 2 août 2026, 08h43</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p>Sur(é)veillé.</p></div>
 </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-2" aria-labelledby="tab-2-2">
 <h4 class="h2">22 juillet 2026, 13h07</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/22-juillet-2026-13h07.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/22-juillet-2026-13h07.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/22-juillet-2026-13h07.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 22 juillet 2026, 13h07</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p>— Google, trouve-moi une station service pour faire le plein.<br >
— Trouvée !<br >
— Ok, merci…<br >
Espagne, juillet 2026.</p></div>
 </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-3" aria-labelledby="tab-2-3">
 <h4 class="h2">21 juillet 2026, 13h53</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/21-juillet-2026-13h53.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/21-juillet-2026-13h53.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/21-juillet-2026-13h53.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 21 juillet 2026, 13h53</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p>Family holidays, les FOMO.</p></div>
 </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-4" aria-labelledby="tab-2-4">
 <h4 class="h2">23 juin 2026, 20h48</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/23-juin-2026-20h48.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/23-juin-2026-20h48.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/23-juin-2026-20h48.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 23 juin 2026, 20h48</span>
 
 </a>
 </div> </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-5" aria-labelledby="tab-2-5">
 <h4 class="h2">2 mars 2026, 09h28</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/2-mars-2026-09h28.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/2-mars-2026-09h28.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/2-mars-2026-09h28.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 2 mars 2026, 09h28</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p>Paris, boulevard de Vaugirard.<br >
<a href="https://link.deezer.com/s/32C1OF9p8U0qBcBqZQ4a4" class="blank">L'amour, l'amour, l'amour</a> Bon Entendeur - Mouloudji</p></div>
 </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-6" aria-labelledby="tab-2-6">
 <h4 class="h2">3 juillet 2025, 08h35</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/3-juillet-2025-08h35.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/3-juillet-2025-08h35.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/3-juillet-2025-08h35.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo 3 juillet 2025, 08h35</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p><strong>Communiquer</strong> : XIV<sup>ème</sup> siècle, au sens de « participer à quelque chose ». Emprunté du latin communicare, « mettre en commun, communiquer », puis « être en relation avec ».</p></div>
 </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-7" aria-labelledby="tab-2-7">
 <h4 class="h2">Bordeaux, 27 juillet 2012, 18h31</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/bordeaux-27-juillet-2012-18h31.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/bordeaux-27-juillet-2012-18h31.jpg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/bordeaux-27-juillet-2012-18h31.jpg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo Bordeaux, 27 juillet 2012, 18h31</span>
 
 </a>
 </div> </div>
 </div>
 <div role="tabpanel" class="outer-line" id="panel-2-8" aria-labelledby="tab-2-8">
 <h4 class="h2">Bordeaux Lac, 10 août 2022, 19h33</h4>
 <div class="flex justify-content-center" data-nosnippet>
 <div class="s-9 l-7 mb-h">
 <a href="/photographie/bordeaux-lac-10-aout-2022-19h33.html" class="ratio-100">
 
 
 <picture>
 <source srcset="https://www.kortic.com/assets/images/card/800/bordeaux-lac-10-aout-2022-19h33.jpeg.webp">
 <img loading="lazy" width="800" class="box-shadow-thin background-color-secondary" src="https://www.kortic.com/assets/images/card/800/bordeaux-lac-10-aout-2022-19h33.jpeg" alt="">
 </picture>
 <span class="screen-readers">Voir les détails de la photo Bordeaux Lac, 10 août 2022, 19h33</span>
 
 </a>
 </div>
 <div class="s-12 markdown"><p>Bordeaux plage.</p></div>
 </div>
 </div>
</section>Les sources Javascript et CSS
Sources Javascript
Taille : 3,10 kilo-octets (~1,19 kilo-octets compressé)
/*
 * Source Kortic (URL : https://www.kortic.com/onglets-et-panneaux-html-accessibles-et-compatibles-seo.html)
 * licence Creative Commons CC BY-NC-SA 4.0
 * https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fr
 */
 
(() => {
 'use strict';
 const FOCUSABLE_SELECTORS = window.FOCUSABLE_SELECTORS ||
 'a[href], area[href], input:not([disabled]):not([type="hidden"]), summary, select:not([disabled]), ' +
 'textarea:not([disabled]), [role="button"], button:not([disabled]), [tabindex="0"], [contenteditable]';
 function switchTabs(tabList, tabs, panels, selectedTab) {
 const targetId = selectedTab.getAttribute('aria-controls');
 const targetPanel = document.getElementById(targetId);
 tabs.forEach(tab => {
 tab.setAttribute('aria-selected', 'false');
 tab.setAttribute('tabindex', '-1');
 });
 selectedTab.setAttribute('aria-selected', 'true');
 selectedTab.removeAttribute('tabindex');
 panels.forEach(panel => {
 panel.setAttribute('aria-hidden', 'true');
 panel.querySelectorAll(FOCUSABLE_SELECTORS).forEach(el => el.setAttribute('tabindex', '-1'));
 });
 if (targetPanel) {
 targetPanel.removeAttribute('aria-hidden');
 const tabbables = targetPanel.querySelectorAll(FOCUSABLE_SELECTORS);
 if (!tabbables.length) targetPanel.setAttribute('tabindex', '0');
 else tabbables.forEach(el => el.removeAttribute('tabindex'));
 }
 tabList.scrollTo({
 left: selectedTab.offsetLeft - (tabList.offsetWidth / 2) + (selectedTab.offsetWidth / 2),
 behavior: 'smooth'
 });
 }
 function initTabs(root, index) {
 const tabList = root.querySelector('[role="tablist"]');
 const tabs = Array.from(tabList.querySelectorAll('[role="tab"]'));
 const panels = Array.from(root.querySelectorAll('[role="tabpanel"]'));
 const auto = root.hasAttribute('data-auto-display');
 const initIndex = parseInt(root.dataset.initTab) || 0;
 const storageKey = root.id ? `data-tab-${index}-${root.id}` : null;
 tabList.addEventListener('keydown', e => {
 const i = tabs.indexOf(document.activeElement);
 if (e.key === 'ArrowLeft') {
 e.preventDefault();
 const prev = i > 0 ? tabs[i - 1] : tabs[tabs.length - 1];
 prev.focus();
 if (auto) switchTabs(tabList, tabs, panels, prev);
 }
 if (e.key === 'ArrowRight') {
 e.preventDefault();
 const next = i < tabs.length - 1 ? tabs[i + 1] : tabs[0];
 next.focus();
 if (auto) switchTabs(tabList, tabs, panels, next);
 }
 });
 tabs.forEach(tab => {
 tab.addEventListener('click', () => {
 switchTabs(tabList, tabs, panels, tab);
 if (storageKey) {
 localStorage.setItem(storageKey, tab.getAttribute('aria-controls'));
 }
 });
 tab.addEventListener('focus', () => {
 if (auto) tab.click();
 });
 });
 const storedId = storageKey && localStorage.getItem(storageKey);
 const tabToActivate = storedId
 ? tabs.find(t => t.getAttribute('aria-controls') === storedId)
 : tabs[initIndex] || tabs[0];
 if (tabToActivate) tabToActivate.click();
 }
 document.addEventListener('DOMContentLoaded', () => {
 document.querySelectorAll('.tabs-panels').forEach((root, i) => {
 initTabs(root, i);
 });
 });
})();
Feuille de styles
/* Les variables CSS sont disponibles ici : 
https://www.kortic.com/assets/styles/custom-vars-kortic.ac57febb2917329e.css
 */
.tabs-panels {
 --panel-radius: var(--radius, 0.3125rem);
 border-radius: var(--panel-radius);
 margin-top: var(--half-gutter) !important;
}
[role="tablist"] {
 border-radius: var(--panel-radius) var(--panel-radius) 0 0;
 padding: 0.3125rem 0 var(--small-gutter, 0.5rem) !important;
 display: flex;
 flex-wrap: nowrap;
 flex-direction: row;
 align-items: center;
 overflow-x: auto;
 overflow-y: hidden;
 -moz-backface-visibility: hidden;
 backface-visibility: hidden;
 -ms-overflow-style: none;
 scrollbar-width: none;
 max-width: calc(100vw - var(--gutter));
}
[role="tablist"]::-webkit-scrollbar {
 display: none;
}
[role="tablist"] button {
 border-radius: var(--panel-radius);
 color: var(--basic-color);
 font-size: 0.9375rem;
 height: var(--button-height, 2.5rem);
 line-height: var(--button-height, 2.5rem);
 padding: 0 calc(var(--button-height, 2.5rem) / 2);
 transition: none;
 white-space: nowrap;
}
[role="tablist"] button + button {
 margin-left: 0.3125rem;
}
[role="tablist"] [aria-selected="true"] {
 background-color: var(--basic-color);
 color: var(--basic-color-reverse);
 box-shadow: none;
 position: relative;
}
[role="tablist"] [aria-selected="true"]:after {
 border: solid transparent;
 border-color: rgba(0, 0, 0, 0);
 border-top-color: var(--basic-color);
 content: "\A0" / "";
 height: 0;
 width: 0;
 position: absolute;
 top: 100%;
 pointer-events: none;
 font-size: 0;
 left: 50%;
 transform: translateX(-50%);
 border-width: var(--small-gutter, 0.5rem);
}
[role="tablist"] button[aria-selected="false"] {
 box-shadow: 0 0 0 1px var(--box-shadow) inset;
 background-color: var(--background-color-secondary, transparent);
}
/* ne pas passer en display none pour garder le SEO */
[role="tabpanel"][aria-hidden="true"] {
 position: absolute !important;
 text-indent: -6.25rem;
 white-space: nowrap;
 z-index: -1;
 height: 1px;
 opacity: 0;
 width: 100%;
 top: 0;
 overflow: hidden;
}
[role="tabpanel"]:focus {
 outline-offset: -0.0625rem;
}
:root.use-keyboard [role="tablist"] button[aria-selected="false"]:focus {
 box-shadow: 0 0 0 3px var(--basic-color) inset;
}
@media (any-hover: hover) {
 [role="tablist"] button[aria-selected="false"]:hover {
 box-shadow: 0 0 0 1px var(--basic-color) inset;
 }
}
Licence Creative commons CC BY-NC-SA 4.0
Lien vers la licence : Creative commons CC BY-NC-SA 4.0
Les sources proposées sur Kortic Anthony Ladeuil sont mises à disposition selon les termes suivants :
- Pas d’utilisation commerciale
-
Vous n'êtes pas autorisé à faire un usage commercial de cette Œuvre, tout ou partie du matériel
la composant.
Bien entendu, la probabilité est faible pour que ce point soit respecté. En cas de sursaut d'honnêteté, vous pouvez payer un café, cette page soulagera votre conscience. - Attribution
- Vous devez créditer l'Œuvre, intégrer un lien vers la licence et indiquer si des modifications ont été effectuées à l'Œuvre. Vous devez indiquer ces informations par tous les moyens raisonnables, sans toutefois suggérer que l'Offrant vous soutient ou soutient la façon dont vous avez utilisé son Œuvre.
- Partage dans les mêmes conditions
-
Dans le cas où vous effectuez un remix, que vous transformez, ou créez à partir du matériel
composant
l'Œuvre originale, vous devez diffuser l'Œuvre modifiée dans les mêmes conditions, c'est-à-dire
avec la même licence avec laquelle l'Œuvre originale a été diffusée.
Pas de restrictions complémentaires Vous n'êtes pas autorisé à appliquer des conditions légales ou des mesures techniques qui restreindraient légalement autrui à utiliser l'Œuvre dans les conditions décrites par la licence.
À défaut de tout ça, un petit message et une référence à Kortic restent les bienvenus.
Limitation de responsabilité
Le code est fourni « tel quel », sans garantie d'aucune sorte, expresse ou implicite. En aucun cas l’auteur ou les détenteurs du copyright ne seront responsables de toute réclamation, dommage ou autre responsabilité, que ce soit dans une action contractuelle, délictuelle ou autre, résultant de, en dehors ou en relation avec le logiciel ou l'utilisation ou d'autres transactions.
Vous aimez cette page ?
Dites-le !
Vous aimez cette page ?
Dites-le !