Éléments interactifs

Popup, Tooltip, Accordion, Tabs et Slider. Tous les éléments sont emboîtables (nestable) et initialisés automatiquement au chargement.

Système de popup/modal avec overlay, fermeture par clic extérieur, touche Escape et bouton. Les popups sont empilables (nestable).

<button data-popup-target="demo">Ouvrir le popup</button>

<div class="popup" data-popup="demo">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <h2>Titre du popup</h2>
    <p>Contenu du popup.</p>
  </div>
</div>
AttributRôle
data-popup-target="id"Bouton qui ouvre le popup correspondant
data-popup="id"Identifiant du popup
data-popup-closeBouton de fermeture (dans le popup)

Fermeture

  • Clic sur .popup__overlay
  • Clic sur [data-popup-close]
  • Touche Escape (ferme le dernier ouvert)

Popups imbriqués

Les popups peuvent être imbriqués. Le z-index est géré automatiquement par CSS (.popup .popup → z-index supérieur). (Le z-index contrôle quel élément s'affiche par-dessus les autres quand ils se superposent. Le framework gère ça automatiquement — vous n'avez pas à vous en soucier.) La touche Escape ferme toujours le dernier popup ouvert.

Variantes de position

Ajoutez data-popup-position sur le .popup pour changer l'animation et la disposition :

ValeurComportement
(aucune)Centré (défaut) — animation scale + fade
rightPanneau latéral droit — pleine hauteur, max 480px, glisse depuis la droite
leftPanneau latéral gauche — pleine hauteur, max 480px, glisse depuis la gauche
bottomBottom sheet — pleine largeur, max 80vh, glisse depuis le bas
topPanneau supérieur — pleine largeur, max 80vh, glisse depuis le haut

Popup centré (défaut)

<button data-popup-target="demo">Ouvrir</button>
<div class="popup" data-popup="demo">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <h2>Titre</h2>
    <p>Contenu du popup.</p>
  </div>
</div>

Panneau droit

<button data-popup-target="menu">Menu</button>
<div class="popup" data-popup="menu" data-popup-position="right">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <h2>Menu</h2>
  </div>
</div>

Panneau gauche

<button data-popup-target="sidebar">Sidebar</button>
<div class="popup" data-popup="sidebar" data-popup-position="left">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <h2>Sidebar</h2>
  </div>
</div>

Bottom sheet

<button data-popup-target="sheet">Bottom sheet</button>
<div class="popup" data-popup="sheet" data-popup-position="bottom">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <p>Contenu en bas.</p>
  </div>
</div>

Panneau haut

<button data-popup-target="top-panel">Panneau haut</button>
<div class="popup" data-popup="top-panel" data-popup-position="top">
  <div class="popup__overlay"></div>
  <div class="popup__content">
    <button class="popup__close" data-popup-close>&times;</button>
    <p>Contenu en haut.</p>
  </div>
</div>

Sur mobile (≤ 767px), les panneaux latéraux passent en pleine largeur automatiquement.

ClasseDescription
.popupConteneur principal (caché par défaut)
.popup--activePopup visible (ajouté par JS)
.popup__overlayFond semi-transparent
.popup__contentBoîte de contenu (animation scale + fade)
.popup__closeBouton de fermeture (positionné en haut à droite)

Attributs récapitulatifs

AttributRôle
data-popup-target="id"Bouton qui ouvre le popup correspondant
data-popup="id"Identifiant du popup
data-popup-closeBouton de fermeture (dans le popup)
data-popup-position="right|left|bottom|top"Variante de position (optionnel)

Tooltip

Bulle d'information au survol ou au focus. Repositionnement automatique si la bulle déborde de la fenêtre.

Utilisation

<button data-tooltip="Texte de la bulle">Survolez-moi</button>

<!-- Avec position -->
<button data-tooltip="Info" data-tooltip-pos="bottom">En bas</button>
<button data-tooltip="Info" data-tooltip-pos="left">À gauche</button>
<button data-tooltip="Info" data-tooltip-pos="right">À droite</button>

Les tooltips fonctionnent sur n'importe quel élément HTML : <span>, <button>, <a>, <div>, etc.

Attributs

AttributDescription
data-tooltip="texte"Texte de la bulle
data-tooltip-posPosition : top (défaut), bottom, left, right

Repositionnement automatique

Si la bulle déborde du viewport, elle se repositionne automatiquement (ex. topbottom si pas de place en haut).

Classes CSS

ClasseDescription
.tooltipAjoutée automatiquement à l'élément parent
.tooltip__bubbleBulle de texte (créée dynamiquement)
.tooltip__bubble--top/bottom/left/rightVariantes de position
.tooltip__bubble--visibleBulle visible (avec transition)

Accordion

Panneaux dépliables avec animation CSS Grid. Support du mode multiple et de l'imbrication.

Contenu du premier panneau. Un seul panneau ouvert à la fois par défaut.
Contenu du deuxième panneau avec un sous-accordion imbriqué :
Contenu imbriqué A.
Contenu imbriqué B (mode multiple).
Contenu du troisième panneau.

Structure HTML

<div class="accordion">
  <div class="accordion__item">
    <button class="accordion__header">Section 1</button>
    <div class="accordion__body">
      <div>Contenu du premier panneau.</div>
    </div>
  </div>
  <div class="accordion__item">
    <button class="accordion__header">Section 2</button>
    <div class="accordion__body">
      <div>Contenu du deuxième panneau.</div>
    </div>
  </div>
  <div class="accordion__item">
    <button class="accordion__header">Section 3</button>
    <div class="accordion__body">
      <div>Contenu du troisième panneau.</div>
    </div>
  </div>
</div>

Mode multiple

Par défaut, un seul panneau est ouvert à la fois. Ajoutez data-accordion-multi pour permettre l'ouverture de plusieurs panneaux simultanément :

<div class="accordion" data-accordion-multi>
  ...
</div>

Accordéon imbriqué

Les accordéons peuvent être imbriqués. Chaque niveau gère ses propres items indépendamment :

<div class="accordion">
  <div class="accordion__item">
    <button class="accordion__header">Parent</button>
    <div class="accordion__body">
      <div>
        <div class="accordion">
          <div class="accordion__item">
            <button class="accordion__header">Enfant</button>
            <div class="accordion__body">
              <div>Contenu imbriqué.</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Classes CSS

ClasseDescription
.accordionConteneur principal (bordure + arrondi)
.accordion__itemUn panneau individuel
.accordion__item--activePanneau ouvert (ajouté par JS)
.accordion__headerEn-tête cliquable (bouton)
.accordion__bodyContenu (animation via grid-template-rows)

Tabs

Système d'onglets avec navigation et panneaux. Support de l'imbrication.

Contenu du premier onglet.

Contenu du deuxième onglet.

Contenu du troisième onglet avec tabs imbriqués :

Contenu imbriqué A.

Contenu imbriqué B.

Scroll automatique

Quand les onglets débordent, la barre de navigation scrolle horizontalement avec des dégradés indicateurs. Le tab actif est automatiquement centré.

Contenu Accueil

Contenu Produits

Contenu Services

Contenu Portfolio

Contenu Témoignages

Contenu Équipe

Contenu Tarifs

Contenu Blog

Contenu Contact

Contenu FAQ

Structure HTML

<div class="tabs">
  <div class="tabs__nav">
    <button class="tabs__tab" data-tab="tab1">Onglet 1</button>
    <button class="tabs__tab" data-tab="tab2">Onglet 2</button>
    <button class="tabs__tab" data-tab="tab3">Onglet 3</button>
  </div>
  <div class="tabs__panel" data-tab-panel="tab1">Contenu 1</div>
  <div class="tabs__panel" data-tab-panel="tab2">Contenu 2</div>
  <div class="tabs__panel" data-tab-panel="tab3">Contenu 3</div>
</div>

Onglet actif par défaut

Par défaut, le premier onglet est actif. Ajoutez data-tab-active pour choisir un autre :

<button class="tabs__tab" data-tab="tab2" data-tab-active>Onglet 2</button>

Attributs

AttributDescription
data-tab="id"Identifiant de l'onglet (sur le bouton)
data-tab-panel="id"Identifiant du panneau associé
data-tab-activeOnglet actif au chargement (optionnel)

Classes CSS

ClasseDescription
.tabsConteneur principal
.tabs__navBarre de navigation (scroll horizontal automatique avec fades indicateurs)
.tabs__nav-wrapperWrapper auto-généré par JS — affiche des dégradés gauche/droite quand la nav déborde
.tabs__tabBouton d'onglet
.tabs__tab--activeOnglet actif (souligné en couleur primaire)
.tabs__panelPanneau de contenu (caché par défaut)
.tabs__panel--activePanneau visible

Accessibilité clavier

Les onglets supportent la navigation clavier complète conformément au pattern WAI‑ARIA Tabs :

  • Flèche droite : focus et active l'onglet suivant (retour au premier en fin de liste)
  • Flèche gauche : focus et active l'onglet précédent (retour au dernier en début de liste)
  • Home : focus et active le premier onglet
  • End : focus et active le dernier onglet

Le pattern roving tabindex est utilisé : l'onglet actif a tabindex="0", les autres tabindex="-1". Les attributs ARIA (role="tablist", role="tab", role="tabpanel", aria-selected, aria-controls) sont générés automatiquement par le JS.

Carousel avec navigation par boutons, dots, swipe tactile, drag souris, autoplay et boucle. Support multi-slides.

Slide 1
Slide 2
Slide 3

Structure HTML

<!-- Slider basique (1 slide visible) -->
<div class="slider">
  <div class="slider__track">
    <div class="slider__slide">Slide 1</div>
    <div class="slider__slide">Slide 2</div>
    <div class="slider__slide">Slide 3</div>
  </div>
  <button class="slider__prev"></button>
  <button class="slider__next"></button>
  <div class="slider__dots"></div>
</div>

Slider multi-slides

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5
Slide 6
<!-- Slider responsive multi-slides -->
<div class="slider"
     data-slider-per-view="3 2 2 1"
     data-slider-loop="true"
     data-slider-drag="true"
     data-slider-gap="md">
  <div class="slider__track">
    <div class="slider__slide">Slide 1</div>
    <div class="slider__slide">Slide 2</div>
    <div class="slider__slide">Slide 3</div>
    <div class="slider__slide">Slide 4</div>
    <div class="slider__slide">Slide 5</div>
    <div class="slider__slide">Slide 6</div>
  </div>
  <button class="slider__prev"></button>
  <button class="slider__next"></button>
  <div class="slider__dots"></div>
</div>

Le format data-slider-per-view="3 2 2 1" définit le nombre de slides visibles par breakpoint : desktop tablette mobile-paysage mobile. Les valeurs cascadent : "3" = 3 slides sur tous les écrans, "3 2" = 3 desktop + 2 pour le reste.

Attributs

AttributValeurDescription
data-slider-per-view"3" ou "4 3 2 1"Slides visibles par breakpoint : desktop [tablet] [mobile-landscape] [mobile]. Cascade auto si moins de 4 valeurs.
data-slider-looptrueBoucle infinie
data-slider-auto3000Défilement auto en ms (pause au survol)
data-slider-dragtrueDrag à la souris (en plus du swipe tactile)
data-slider-gapxs | sm | md | lg | xlEspacement entre les slides
data-slider-dotsfalseMasquer les dots de navigation
data-slider-arrowsfalseMasquer les flèches de navigation
data-slider-arrow-posoverlay | outside | top-left | top-center | top-right | bottom-left | bottom-center | bottom-right | left | rightPosition des flèches de navigation (défaut : overlay)

Personnalisation des flèches

Les flèches utilisent par défaut les icônes chevron. Personnalisez-les via ces attributs sur le .slider :

AttributValeurDescription
data-slider-arrow-prevNom d'icôneIcône du bouton précédent (ex : arrow-left)
data-slider-arrow-nextNom d'icôneIcône du bouton suivant (ex : arrow-right)
data-slider-arrow-typeoutline | solidType d'icône (défaut : outline)
data-slider-arrow-sizeNombre en pxTaille de l'icône SVG (défaut : 20)
Slide 1
Slide 2
Slide 3
Slide 4
<div class="slider"
     data-slider-arrow-prev="arrow-left"
     data-slider-arrow-next="arrow-right"
     style="--slider-arrow-color: #fff; --slider-arrow-bg: var(--color-primary); --slider-arrow-hover-bg: var(--color-primary-dark);">
  ...
</div>

Les icônes sont chargées depuis le système d'icônes (icons.js). Les styles peuvent aussi être définis via les CSS custom properties --slider-arrow-* directement en CSS.

Position des flèches

Par défaut, les flèches sont superposées aux slides (mode overlay). L'attribut data-slider-arrow-pos permet de les repositionner :

ValeurComportement
(aucune) / overlayFlèches centrées verticalement sur les slides (défaut)
outsideFlèches centrées verticalement mais à l'extérieur des slides
top-leftFlèches au-dessus du slider, alignées à gauche
top-centerFlèches au-dessus du slider, centrées
top-rightFlèches au-dessus du slider, alignées à droite
bottom-leftFlèches sous les dots, alignées à gauche
bottom-centerFlèches sous les dots, centrées
bottom-rightFlèches sous les dots, alignées à droite
leftFlèches à gauche, dots à droite (même ligne, dots scrollables)
rightFlèches à droite, dots à gauche (même ligne, dots scrollables)

Pour les positions top-* et bottom-*, les flèches sont sur une ligne séparée des dots. Pour les positions left et right, les flèches et les dots partagent la même ligne (avec scroll horizontal si les dots débordent).

Position : top-right

Slide 1
Slide 2
Slide 3
Slide 4

Position : bottom-right (flèches sous les dots)

Slide 1
Slide 2
Slide 3
Slide 4

Position : left (flèches à gauche, dots à droite)

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5
Slide 6
Slide 7
Slide 8

Position : right (dots à gauche, flèches à droite)

Slide 1
Slide 2
Slide 3
Slide 4
Slide 5
Slide 6
Slide 7
Slide 8

Position : outside

Slide 1
Slide 2
Slide 3
Slide 4
<!-- Flèches en haut à droite -->
<div class="slider" data-slider-arrow-pos="top-right">
  ...
</div>

<!-- Flèches en bas (sous les dots) -->
<div class="slider" data-slider-arrow-pos="bottom-right">
  ...
</div>

<!-- Flèches à gauche, dots à droite (même ligne) -->
<div class="slider" data-slider-arrow-pos="left">
  ...
</div>

<!-- Dots à gauche, flèches à droite (même ligne) -->
<div class="slider" data-slider-arrow-pos="right">
  ...
</div>

<!-- Flèches à l'extérieur -->
<div class="slider" data-slider-arrow-pos="outside">
  ...
</div>

CSS custom properties

VariableDescription
--slider-arrow-sizeTaille du bouton
--slider-arrow-colorCouleur de l'icône
--slider-arrow-hover-colorCouleur au survol
--slider-arrow-bgFond du bouton
--slider-arrow-hover-bgFond au survol
--slider-arrow-borderCouleur de bordure
  • Boutons : .slider__prev et .slider__next (optionnels)
  • Dots : .slider__dots (générés automatiquement par JS, optionnel)
  • Swipe : tactile natif (seuil 50px)
  • Drag souris : activé via data-slider-drag="true"

Exemple complet

<div class="slider"
     data-slider-per-view="2"
     data-slider-loop="true"
     data-slider-auto="4000"
     data-slider-drag="true"
     data-slider-gap="md"
     data-slider-arrow-prev="arrow-left"
     data-slider-arrow-next="arrow-right"
     style="--slider-arrow-color: #fff; --slider-arrow-bg: var(--color-primary); --slider-arrow-hover-bg: var(--color-primary-dark);">
  <div class="slider__track">
    <div class="slider__slide"><img src="img/1.jpg" alt=""></div>
    <div class="slider__slide"><img src="img/2.jpg" alt=""></div>
    <div class="slider__slide"><img src="img/3.jpg" alt=""></div>
    <div class="slider__slide"><img src="img/4.jpg" alt=""></div>
  </div>
  <button class="slider__prev"></button>
  <button class="slider__next"></button>
  <div class="slider__dots"></div>
</div>

Classes CSS

ClasseDescription
.sliderConteneur principal (overflow: hidden)
.slider__trackPiste flex (translateX pour la navigation)
.slider__slideUn slide individuel
.slider__prev, .slider__nextBoutons flèches (positionnés en absolu)
.slider__nav-wrapConteneur des flèches (généré par JS pour les positions bottom-*)
.slider__dotsConteneur des points de navigation
.slider__dotPoint individuel (créé par JS)
.slider__dot--activePoint actif

API JavaScript

FonctionFichierDescription
initElements(root)elements.jsInitialise popups, tooltips, accordions, tabs, sliders dans root (défaut : document).
initAnimations(root)animations.jsInitialise les animations scroll + clic dans root.
initIcons(root)icons.jsCharge les icônes SVG [data-icon] dans root.
initForms(root)forms.jsInitialise formulaires, validation, multi-steps dans root.
initInteractions(root)interactions.jsInitialise les interactions déclaratives [data-interact] dans root.
renderComponents(root)components.jsRend les [data-component] dans root.
showToast(message, type, duration)forms.jsAffiche une notification toast. Types : 'success', 'error', 'warning', 'info'.
toggleTheme()darkmode.jsBascule entre light et dark mode.
openCookieSettings()cookies.jsOuvre le panneau de gestion des cookies.
getUrlParams()params.jsRetourne un objet avec tous les paramètres URL.
getUTMs()params.jsRetourne un objet avec les UTMs persistants.
fetchIconSvg(type, name, cb)icons.jsRécupère le SVG brut d'une icône via callback.
registerComponent(name, fn)components.jsEnregistre un composant. fn(slots) retourne du HTML.
escapeSlotHtml(str)components.jsÉchappe les caractères HTML (anti-XSS pour les slots texte).

Toutes ces fonctions sont appelées automatiquement au DOMContentLoaded. Appelez‑les manuellement après avoir injecté du HTML dynamique :

// Après injection de HTML dynamique
initElements(monConteneur);
initAnimations(monConteneur);
initIcons(monConteneur);
initInteractions(monConteneur);

Inclure dans une page

<link rel="stylesheet" href="core/css/elements.css">
<script src="core/js/elements.js" defer></script>

Problèmes courants

  • Le slider ne fonctionne pas : vérifiez que elements.js est chargé avec defer. La classe .slider doit être présente sur le conteneur.
  • Le popup ne s'ouvre pas : le data-popup-target du bouton doit correspondre exactement au data-popup du popup.
  • Les tabs ne changent pas : chaque data-tab doit avoir un data-tab-panel correspondant avec la même valeur.
  • L'accordion ne se déplie pas : l'attribut data-accordion-multi est nécessaire pour permettre l'ouverture simultanée de plusieurs panneaux.
  • Le slider drag ne marche pas sur mobile : ajoutez data-slider-drag="true" au conteneur.

Accessibilité

  • Les popups se ferment avec la touche Escape.
  • Les accordions s'ouvrent/ferment au clic.
  • Les tooltips apparaissent au focus clavier en plus du hover.
  • Les tabs supportent la navigation clavier complète (flèches, Home, End) avec roving tabindex et attributs WAI‑ARIA.
  • Les sliders se contrôlent via les boutons, le drag tactile et l'autoplay.
  • Le header mobile met à jour aria-expanded et aria-label sur le burger, se ferme via Escape avec retour du focus.
  • Toutes les animations respectent prefers-reduced-motion.

Header mobile

Le module Header Mobile gère l'ouverture et la fermeture du menu de navigation sur mobile (burger menu). Il est initialisé automatiquement si un élément .header contenant un bouton [data-header-toggle] est présent dans la page.

Attributs

AttributRôle
data-header-toggleBouton burger qui ouvre/ferme le menu
data-header-overlayOverlay semi-transparent derrière le menu (optionnel)

Comportement

  • Clic sur le burger : ajoute la classe .header--open sur le .header, verrouille le scroll de la page
  • Clic sur l'overlay : ferme le menu et déverrouille le scroll
  • Touche Escape : ferme le menu et remet le focus sur le burger
  • Redimensionnement au-dessus du breakpoint tablette : ferme automatiquement le menu
  • Clic sur un lien de navigation : ferme automatiquement le menu

Accessibilité

Le burger met à jour aria-expanded (true/false) et aria-label (« Ouvrir le menu » / « Fermer le menu ») à chaque changement d'état.

Markup

Le composant Header (components/header.js) inclut déjà le markup correct avec data-header-toggle et data-header-overlay. Aucune configuration supplémentaire n'est nécessaire si vous utilisez le composant standard.

<header class="header">
  <button data-header-toggle aria-expanded="false" aria-label="Ouvrir le menu">
    <!-- Icône burger -->
  </button>
  <nav class="header__nav">
    <!-- Liens de navigation -->
  </nav>
  <div data-header-overlay></div>
</header>

Classes CSS

ClasseDescription
.headerConteneur principal du header
.header--openÉtat ouvert (ajouté par JS) — affiche la nav et l'overlay

Voir aussi