Éléments interactifs et widgets dans le développement web
Créez des widgets accessibles en JavaScript — sliders, modales, onglets, accordéons — ainsi que l'API Canvas pour des graphiques dynamiques, avec des exemples prenant en charge le clavier.
Créer des widgets personnalisés et exploiter les API HTML peut considérablement améliorer l'interactivité et l'expérience utilisateur de vos applications web. Ce guide fournit des instructions pas à pas pour créer des éléments interactifs personnalisés comme des sliders, des modales et des onglets, et vous présente les API HTML5 telles que l'API Canvas pour la création de graphiques dynamiques.
Introduction
Un widget est un composant d'interface utilisateur interactif autonome — un slider, une boîte de dialogue modale, un panneau à onglets, un accordéon — que l'utilisateur peut utiliser pour modifier ce qu'il voit ou saisir des données. Les navigateurs proposent quelques widgets natifs (<input type="range">, <dialog>, <details>), mais vous en créerez souvent de personnalisés lorsque vous avez besoin d'un comportement, d'un style ou d'une mise en page que les éléments intégrés ne fournissent pas.
Ce guide montre comment créer les trois widgets que vous utiliserez le plus souvent — un slider, une modale et un ensemble d'onglets — puis présente l'API Canvas, une fonctionnalité HTML5 pour dessiner des graphiques dynamiques. Chaque exemple câble le comportement avec le DOM et la gestion des événements, il est donc utile d'être à l'aise avec la sélection d'éléments et les événements du navigateur au préalable.
Widget natif ou widget personnalisé ?
Préférez un élément natif avant d'écrire du JavaScript. Les widgets natifs sont accessibles, utilisables au clavier et compatibles avec les formulaires nativement, et ils continuent de fonctionner même si votre script ne se charge pas.
| Besoin | Élément natif | Créer un widget personnalisé quand… |
|---|---|---|
| Choisir une valeur dans une plage | <input type="range"> | vous avez besoin d'un contrôle à deux curseurs ou non linéaire |
| Afficher une boîte de dialogue bloquante | <dialog> + showModal() | vous avez besoin d'une mise en page ou d'une animation entièrement personnalisée |
| Section repliable | <details> / <summary> | vous avez besoin d'un groupe d'accordéons animés |
| Onglets | (pas d'élément natif) | toujours personnalisé — suivez le modèle ARIA tabs |
L'exemple de slider ci-dessous encapsule en réalité le <input type="range"> natif, ce qui est l'approche recommandée. La modale et les onglets sont construits de zéro pour que vous puissiez voir les mécanismes, mais en production préférez <dialog> pour les modales.
Bonnes pratiques
- Utiliser du HTML sémantique : Assurez-vous que votre structure HTML est significative et accessible.
- Séparer les préoccupations : Gardez HTML, CSS et JavaScript séparés pour maintenir un code propre et gérable.
- Accessibilité : Assurez-vous que les éléments interactifs sont accessibles à tous les utilisateurs, y compris ceux utilisant des lecteurs d'écran.
- Optimisation des performances : Minimisez la manipulation du DOM et optimisez le JavaScript pour garantir des interactions fluides.
- Conception responsive : Assurez-vous que les éléments interactifs fonctionnent bien sur différentes tailles d'écran et appareils.
Créer des widgets personnalisés
Pour les applications en production, considérez en premier les éléments HTML natifs : <dialog> pour les modales, et <details> / <summary> pour le contenu repliable. Ils vous offrent gratuitement la gestion du focus, la touche Échap et la navigation au clavier.
Slider personnalisé
Un slider personnalisé permet aux utilisateurs de sélectionner une valeur dans une plage. Voici comment en créer un avec HTML, CSS et JavaScript.
Exemple
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Slider</title>
<style>
.slider-container {
display: flex;
align-items: center;
gap: 10px;
}
#slider {
width: 200px;
}
</style>
</head>
<body>
<div class="slider-container">
<input type="range" id="slider" min="0" max="100" value="50" aria-label="Value slider" aria-describedby="slider-value" />
<span id="slider-value">50</span>
</div>
<script>
document.getElementById('slider').addEventListener('input', function() {
document.getElementById('slider-value').textContent = this.value;
});
</script>
</body>
</html>Cet exemple crée un slider simple avec un input de type range et un span pour afficher la valeur actuelle. Le JavaScript met à jour le contenu textuel du span au fur et à mesure que le slider se déplace.
Modale personnalisée
Les modales sont utilisées pour afficher du contenu dans une superposition. Voici comment créer une modale personnalisée.
Exemple
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Modal</title>
<style>
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background-color: #fff;
padding: 20px;
border-radius: 5px;
text-align: center;
}
.close {
position: absolute;
top: 10px;
right: 10px;
font-size: 20px;
cursor: pointer;
}
</style>
</head>
<body>
<button id="open-modal">Open Modal</button>
<div id="modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" tabindex="-1">
<div class="modal-content">
<span id="close-modal" class="close" aria-label="Close modal">×</span>
<h2 id="modal-title">Custom Modal</h2>
<p>This is a custom modal!</p>
</div>
</div>
<script>
const modal = document.getElementById('modal');
const openBtn = document.getElementById('open-modal');
const closeBtn = document.getElementById('close-modal');
openBtn.addEventListener('click', () => {
modal.style.display = 'flex';
closeBtn.focus();
});
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
openBtn.focus();
});
window.addEventListener('keydown', (e) => {
if (modal.style.display === 'flex' && e.key === 'Escape') {
modal.style.display = 'none';
openBtn.focus();
}
});
modal.addEventListener('click', (event) => {
if (event.target === modal) {
modal.style.display = 'none';
openBtn.focus();
}
});
</script>
</body>
</html>Cet exemple montre comment créer une modale pouvant être ouverte et fermée avec JavaScript. La modale affiche une superposition et une boîte de contenu, qui peut être fermée en cliquant sur un bouton, en appuyant sur Échap ou en cliquant sur la superposition. Le focus est géré pour permettre aux utilisateurs au clavier de naviguer dans la boîte de dialogue.
Onglets personnalisés
Les onglets permettent aux utilisateurs de naviguer entre différentes sections de contenu. Voici comment créer des onglets personnalisés.
Exemple
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Tabs</title>
<style>
.tabs {
display: flex;
gap: 10px;
}
.tab-button {
padding: 10px 20px;
cursor: pointer;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 5px;
}
.tab-button.active {
background-color: #fff;
border-bottom: 2px solid #000;
}
.tab-content {
display: none;
margin-top: 20px;
}
.tab-content.active {
display: block;
}
</style>
</head>
<body>
<div class="tabs" role="tablist">
<button class="tab-button active" role="tab" aria-selected="true" data-tab="tab1">Tab 1</button>
<button class="tab-button" role="tab" aria-selected="false" data-tab="tab2">Tab 2</button>
<button class="tab-button" role="tab" aria-selected="false" data-tab="tab3">Tab 3</button>
</div>
<div class="tab-content active" role="tabpanel" aria-labelledby="tab1">
<p>Content for Tab 1</p>
</div>
<div class="tab-content" role="tabpanel" aria-labelledby="tab2">
<p>Content for Tab 2</p>
</div>
<div class="tab-content" role="tabpanel" aria-labelledby="tab3">
<p>Content for Tab 3</p>
</div>
<script>
// Array.from is important: querySelectorAll returns a NodeList,
// which has no .indexOf method. We need a real array for the
// arrow-key navigation below.
const buttons = Array.from(document.querySelectorAll('.tab-button'));
const contents = document.querySelectorAll('.tab-content');
function activateTab(clickedBtn) {
buttons.forEach(btn => {
btn.classList.remove('active');
btn.setAttribute('aria-selected', 'false');
});
contents.forEach(content => content.classList.remove('active'));
clickedBtn.classList.add('active');
clickedBtn.setAttribute('aria-selected', 'true');
document.getElementById(clickedBtn.dataset.tab).classList.add('active');
}
buttons.forEach(button => {
button.addEventListener('click', () => activateTab(button));
button.addEventListener('keydown', (e) => {
let nextIndex;
if (e.key === 'ArrowRight') nextIndex = (buttons.indexOf(button) + 1) % buttons.length;
else if (e.key === 'ArrowLeft') nextIndex = (buttons.indexOf(button) - 1 + buttons.length) % buttons.length;
else return;
e.preventDefault();
buttons[nextIndex].focus();
activateTab(buttons[nextIndex]);
});
});
</script>
</body>
</html>Cet exemple crée une interface à onglets. Cliquer sur un bouton d'onglet ou utiliser les touches fléchées gauche/droite affiche le contenu correspondant et masque les autres. La gestion des touches fléchées suit le modèle ARIA tabs du WAI-ARIA, ce qui permet aux utilisateurs au clavier de se déplacer entre les onglets sans souris — un élément clé de l'accessibilité du DOM.
Accordéon avec <details> natif
Tous les widgets repliables n'ont pas besoin de JavaScript. L'élément natif <details> vous offre une bascule ouverture/fermeture, la navigation au clavier et la sémantique appropriée sans aucun script. Utilisez-le pour les FAQ et les panneaux de divulgation.
Exemple
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Accordion</title>
</head>
<body>
<details>
<summary>What is a widget?</summary>
<p>A self-contained interactive UI component.</p>
</details>
<details>
<summary>Do I always need JavaScript?</summary>
<p>No — native elements like this one work without any script.</p>
</details>
<script>
// Optional: react when a panel opens (e.g. lazy-load content).
document.querySelectorAll('details').forEach((d) => {
d.addEventListener('toggle', () => {
console.log(d.open ? 'opened' : 'closed');
});
});
</script>
</body>
</html>L'événement toggle se déclenche chaque fois que l'utilisateur développe ou réduit un panneau, vous pouvez donc charger du contenu en différé ou suivre les analyses. N'optez pour un accordéon scripté que lorsque vous avez besoin d'animation ou d'un comportement « un seul panneau ouvert à la fois ».
Utiliser les API HTML5
Introduction aux API HTML5
Les API HTML5 offrent des fonctionnalités puissantes qui améliorent les applications web. L'une des API HTML5 les plus polyvalentes est l'API Canvas, qui permet la création de graphiques dynamiques.
Utiliser l'API Canvas
L'API Canvas vous permet de dessiner des graphiques directement sur une page web. Voici un exemple de base d'utilisation de l'API Canvas.
Exemple
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Canvas API Example</title>
</head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #000;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// Draw a rectangle
ctx.fillStyle = '#FF0000';
ctx.fillRect(50, 50, 150, 100);
// Draw a circle
ctx.beginPath();
ctx.arc(200, 200, 40, 0, 2 * Math.PI);
ctx.fillStyle = '#00FF00';
ctx.fill();
// Draw text
ctx.font = '20px Arial';
ctx.fillStyle = '#0000FF';
ctx.fillText('Hello Canvas', 100, 300);
</script>
</body>
</html>Cet exemple illustre les fonctions de dessin de base de l'API Canvas :
fillRect(x, y, width, height)dessine un rectangle rempli dont le coin supérieur gauche est en(x, y).arc(x, y, radius, startAngle, endAngle)ajoute un tracé de cercle centré en(x, y); les angles sont en radians, donc un cercle complet va de0à2 * Math.PI. Vous devez appelerbeginPath()avant etfill()(oustroke()) après.fillText(text, x, y)dessine du texte, où(x, y)est le point de départ de la ligne de base, et non le coin supérieur gauche.
Un piège courant : définissez fillStyle avant l'appel de dessin qu'il doit affecter — le canvas conserve la dernière couleur définie, il est donc facile d'utiliser accidentellement une même couleur sur plusieurs formes. Pour les animations, effacez le cadre précédent avec ctx.clearRect(0, 0, canvas.width, canvas.height) et redessinez à l'intérieur de requestAnimationFrame. Définir la taille du canvas en CSS plutôt qu'avec les attributs width/height étire le dessin — dimensionnez-le toujours avec les attributs.
Assurez-vous toujours que vos éléments interactifs sont accessibles. Utilisez les rôles et propriétés ARIA, le HTML sémantique et veillez à la navigabilité au clavier pour offrir une expérience utilisateur inclusive à tous. Cela améliore non seulement l'accessibilité, mais renforce également l'utilisabilité générale et le SEO.
Conclusion
Les widgets personnalisés — sliders, modales, onglets, accordéons — et les API HTML5 comme Canvas vous permettent de créer les surfaces interactives dont les applications web modernes ont besoin. La leçon commune à tous ces exemples est la même : commencez par un élément natif lorsqu'il en existe un, puis ajoutez JavaScript uniquement pour le comportement que le navigateur ne vous fournit pas, et ne négligez jamais la navigation au clavier et le support ARIA.
Pour aller plus loin, consultez les techniques de manipulation du DOM pour les blocs de construction utilisés par ces widgets, la gestion des événements dans le DOM pour comprendre comment les entrées utilisateur sont câblées, et l'optimisation des performances du DOM pour maintenir des interactions fluides.