Éléments interactifs
Popup, Tooltip, Accordion, Tabs et Slider. Tous les éléments sont emboîtables (nestable) et initialisés automatiquement au chargement.
Popup / Modal
Système de popup/modal avec overlay, fermeture par clic extérieur, touche Escape et bouton. Les popups sont empilables (nestable).
Titre du popup
Contenu du popup centré. Cliquez en dehors, sur × ou Escape pour fermer.
Structure HTML
<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>×</button>
<h2>Titre du popup</h2>
<p>Contenu du popup.</p>
</div>
</div>
Attributs
| Attribut | Rôle |
|---|---|
data-popup-target="id" | Bouton qui ouvre le popup correspondant |
data-popup="id" | Identifiant du popup |
data-popup-close | Bouton 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). La touche Escape ferme toujours le dernier popup ouvert.
Variantes de position
Panneau droit
Panneau latéral glissant depuis la droite.
Panneau gauche
Panneau latéral glissant depuis la gauche.
Bottom sheet
Panneau glissant depuis le bas.
Panneau haut
Panneau glissant depuis le haut.
Ajoutez data-popup-position sur le .popup pour changer l'animation et la disposition :
| Valeur | Comportement |
|---|---|
| (aucune) | Centré (défaut) — animation scale + fade |
right | Panneau latéral droit — pleine hauteur, max 480px, glisse depuis la droite |
left | Panneau latéral gauche — pleine hauteur, max 480px, glisse depuis la gauche |
bottom | Bottom sheet — pleine largeur, max 80vh, glisse depuis le bas |
top | Panneau 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>×</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>×</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>×</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>×</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>×</button>
<p>Contenu en haut.</p>
</div>
</div>
Sur mobile (≤ 767px), les panneaux latéraux passent en pleine largeur automatiquement.
Classes CSS
| Classe | Description |
|---|---|
.popup | Conteneur principal (caché par défaut) |
.popup--active | Popup visible (ajouté par JS) |
.popup__overlay | Fond semi-transparent |
.popup__content | Boîte de contenu (animation scale + fade) |
.popup__close | Bouton de fermeture (positionné en haut à droite) |
Attributs récapitulatifs
| Attribut | Rôle |
|---|---|
data-popup-target="id" | Bouton qui ouvre le popup correspondant |
data-popup="id" | Identifiant du popup |
data-popup-close | Bouton 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
<span data-tooltip="Texte de la bulle">Survolez-moi</span>
<!-- Avec position -->
<span data-tooltip="Info" data-tooltip-pos="bottom">En bas</span>
<span data-tooltip="Info" data-tooltip-pos="left">À gauche</span>
<span data-tooltip="Info" data-tooltip-pos="right">À droite</span>
Attributs
| Attribut | Description |
|---|---|
data-tooltip="texte" | Texte de la bulle |
data-tooltip-pos | Position : top (défaut), bottom, left, right |
Repositionnement automatique
Si la bulle déborde du viewport, elle se repositionne automatiquement (ex. top → bottom si pas de place en haut).
Classes CSS
| Classe | Description |
|---|---|
.tooltip | Ajoutée automatiquement à l'élément parent |
.tooltip__bubble | Bulle de texte (créée dynamiquement) |
.tooltip__bubble--top/bottom/left/right | Variantes de position |
.tooltip__bubble--visible | Bulle visible (avec transition) |
Accordion
Panneaux dépliables avec animation CSS Grid. Support du mode multiple et de l'imbrication.
Structure HTML
<div class="accordion">
<div class="accordion__item">
<button class="accordion__header">Section 1</button>
<div class="accordion__body">
<div>Contenu du panneau 1.</div>
</div>
</div>
<div class="accordion__item">
<button class="accordion__header">Section 2</button>
<div class="accordion__body">
<div>Contenu du panneau 2.</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
| Classe | Description |
|---|---|
.accordion | Conteneur principal (bordure + arrondi) |
.accordion__item | Un panneau individuel |
.accordion__item--active | Panneau ouvert (ajouté par JS) |
.accordion__header | En-tête cliquable (bouton) |
.accordion__body | Contenu (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
| Attribut | Description |
|---|---|
data-tab="id" | Identifiant de l'onglet (sur le bouton) |
data-tab-panel="id" | Identifiant du panneau associé |
data-tab-active | Onglet actif au chargement (optionnel) |
Classes CSS
| Classe | Description |
|---|---|
.tabs | Conteneur principal |
.tabs__nav | Barre de navigation (scroll horizontal automatique avec fades indicateurs) |
.tabs__nav-wrapper | Wrapper auto-généré par JS — affiche des dégradés gauche/droite quand la nav déborde |
.tabs__tab | Bouton d'onglet |
.tabs__tab--active | Onglet actif (souligné en couleur primaire) |
.tabs__panel | Panneau de contenu (caché par défaut) |
.tabs__panel--active | Panneau visible |
Slider / Carousel
Carousel avec navigation par boutons, dots, swipe tactile, drag souris, autoplay et boucle. Support multi-slides.
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 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
| Attribut | Valeur | Description |
|---|---|---|
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-loop | true | Boucle infinie |
data-slider-auto | 3000 | Défilement auto en ms (pause au survol) |
data-slider-drag | true | Drag à la souris (en plus du swipe tactile) |
data-slider-gap | xs | sm | md | lg | xl | Espacement entre les slides |
data-slider-dots | false | Masquer les dots de navigation |
data-slider-arrows | false | Masquer les flèches de navigation |
Personnalisation des flèches
Les flèches utilisent par défaut les icônes chevron. Personnalisez-les via ces attributs sur le .slider :
| Attribut | Valeur | Description |
|---|---|---|
data-slider-arrow-prev | Nom d'icône | Icône du bouton précédent (ex: arrow-left) |
data-slider-arrow-next | Nom d'icône | Icône du bouton suivant (ex: arrow-right) |
data-slider-arrow-type | outline | solid | Type d'icône (défaut : outline) |
data-slider-arrow-size | Nombre en px | Taille de l'icône SVG (défaut : 20) |
<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);">
...
</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.
CSS custom properties
| Variable | Description |
|---|---|
--slider-arrow-size | Taille du bouton |
--slider-arrow-color | Couleur de l'icône |
--slider-arrow-hover-color | Couleur au survol |
--slider-arrow-bg | Fond du bouton |
--slider-arrow-hover-bg | Fond au survol |
--slider-arrow-border | Couleur de bordure |
Navigation
- Boutons :
.slider__prevet.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);">
<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
| Classe | Description |
|---|---|
.slider | Conteneur principal (overflow: hidden) |
.slider__track | Piste flex (translateX pour la navigation) |
.slider__slide | Un slide individuel |
.slider__prev, .slider__next | Boutons flèches (positionnés en absolu) |
.slider__dots | Conteneur des points de navigation |
.slider__dot | Point individuel (créé par JS) |
.slider__dot--active | Point actif |
API JavaScript
| Fonction | Fichier | Description |
|---|---|---|
initElements(root) | elements.js | Initialise popups, tooltips, accordions, tabs, sliders dans root (défaut : document). |
initAnimations(root) | animations.js | Initialise les animations scroll + clic dans root. |
initIcons(root) | icons.js | Charge les icônes SVG [data-icon] dans root. |
initForms(root) | forms.js | Initialise formulaires, validation, multi-steps dans root. |
renderComponents(root) | components.js | Rend les [data-component] dans root. |
showToast(message, type, duration) | forms.js | Affiche une notification toast. Types : 'success', 'error', 'warning', 'info'. |
toggleTheme() | darkmode.js | Bascule entre light et dark mode. |
openCookieSettings() | cookies.js | Ouvre le panneau de gestion des cookies. |
getUrlParams() | params.js | Retourne un objet avec tous les paramètres URL. |
getUTMs() | params.js | Retourne un objet avec les UTMs persistants. |
fetchIconSvg(type, name, cb) | icons.js | Récupère le SVG brut d'une icône via callback. |
registerComponent(name, fn) | components.js | Enregistre 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);
Inclure dans une page
<link rel="stylesheet" href="core/css/elements.css">
<script src="core/js/elements.js" defer></script>
- Le slider ne fonctionne pas : vérifiez que
elements.jsest chargé avecdefer. La classe.sliderdoit être présente sur le conteneur. - Le popup ne s'ouvre pas : le
data-popup-targetdu bouton doit correspondre exactement audata-popupdu popup. - Les tabs ne changent pas : chaque
data-tabdoit avoir undata-tab-panelcorrespondant avec la même valeur. - L'accordion ne se déplie pas : l'attribut
data-accordion-multiest 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 changent de panneau au clic.
- Les sliders se contrôlent via les boutons, le drag tactile et l'autoplay.
- Toutes les animations respectent
prefers-reduced-motion.