[Nom du Composant]
[Nom du Composant]
Documentation technique
Type de ressource : Composant Astro (UI atomique / Îlot interactif)
Fichier source :src/components/[ui|interactive]/[NomComposant].astro
Statut : [Actif / Déprécié / En développement]
1. Vue d’ensemble
1.1. Description
[Description concise du rôle de ce composant dans l’interface utilisateur]
1.2. Objectif
- [Objectif principal : ex. afficher un bouton d’action réutilisable]
- [Bénéfice pour l’UX ou l’architecture]
1.3. Caractéristiques
| Propriété | Valeur |
|---|---|
| Type | [UI atomique / Îlot interactif] |
| Hydratation | [Aucune / client:load / client:visible / client:idle] |
| Framework JS | [Aucun / React / Vue / Svelte / Web Component] |
| Accessibilité | [WCAG AA conforme / Partiellement conforme / Non testé] |
| Responsive | [Mobile-first / Desktop-first] |
2. Architecture et structure
2.1. Emplacement dans l’arborescence
src/components/├── ui/ # Composants atomiques (HTML + CSS purs)│ ├── Button.astro│ ├── Badge.astro│ └── [NomComposant].astro└── interactive/ # Îlots dynamiques (React/Vue/Svelte) ├── MobileNav.tsx ├── Carousel.tsx └── [NomComposant].tsx2.2. Composants dépendants
| Composant parent | Fichier | Relation |
|---|---|---|
| [Nom du parent] | src/components/[chemin] |
[Composition / Wrapper] |
2.3. Composants enfants utilisés
| Composant enfant | Fichier | Rôle |
|---|---|---|
| [Nom de l’enfant] | src/components/[chemin] |
[Description] |
3. Implémentation
3.1. Variante : Composant UI atomique (HTML + CSS purs)1/2
3.1. Variante : Composant UI atomique (HTML + CSS purs)2/2
---interface Props { label: string; variant?: 'primary' | 'secondary' | 'outline'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; href?: string; onClick?: () => void;}
const { label, variant = 'primary', size = 'md', disabled = false, href, onClick,} = Astro.props;
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';
const variantClasses = { primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500', secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500', outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50 focus:ring-blue-500',};
const sizeClasses = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg',};
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`;---
{href ? ( <a href={href} class={classes} aria-disabled={disabled} > {label} </a>) : ( <button class={classes} disabled={disabled} onClick={onClick} > {label} </button>)}3.2. Variante : Îlot interactif (React)1/2
3.2. Variante : Îlot interactif (React)2/2
import { useState } from 'react';
interface Props { items: Array<{ id: string; title: string; content: string; }>; autoPlay?: boolean; interval?: number;}
export default function Carousel({ items, autoPlay = true, interval = 5000 }: Props) { const [currentIndex, setCurrentIndex] = useState(0);
const nextSlide = () => { setCurrentIndex((prev) => (prev + 1) % items.length); };
const prevSlide = () => { setCurrentIndex((prev) => (prev - 1 + items.length) % items.length); };
// Auto-play useState(() => { if (autoPlay) { const timer = setInterval(nextSlide, interval); return () => clearInterval(timer); } }, [autoPlay, interval]);
return ( <div className="carousel" role="region" aria-label="Carrousel" aria-roledescription="carousel"> <div className="carousel-track"> {items.map((item, index) => ( <div key={item.id} className={`carousel-slide ${index === currentIndex ? 'active' : ''}`} role="group" aria-roledescription="slide" aria-label={`${index + 1} sur ${items.length}`} aria-hidden={index !== currentIndex} > <h3>{item.title}</h3> <p>{item.content}</p> </div> ))} </div>
<button onClick={prevSlide} aria-label="Diapositive précédente" className="carousel-prev" > ← </button>
<button onClick={nextSlide} aria-label="Diapositive suivante" className="carousel-next" > → </button>
<div className="carousel-indicators"> {items.map((_, index) => ( <button key={index} onClick={() => setCurrentIndex(index)} className={`indicator ${index === currentIndex ? 'active' : ''}`} aria-label={`Aller à la diapositive ${index + 1}`} aria-current={index === currentIndex} /> ))} </div> </div> );}3.3. Utilisation dans une page
---import Button from '../components/ui/Button.astro';import Carousel from '../components/interactive/Carousel';
const items = [ { id: '1', title: 'Témoignage 1', content: 'Contenu...' }, { id: '2', title: 'Témoignage 2', content: 'Contenu...' },];---
<!-- Composant UI (pas d'hydratation) --><Button label="En savoir plus" variant="primary" href="/about" />
<!-- Îlot interactif (hydratation différée) --><Carousel client:visible items={items} autoPlay={true} interval={5000} />4. Props et interface
4.1. Props obligatoires
| Prop | Type | Description | Exemple |
|---|---|---|---|
label |
string |
Texte affiché dans le bouton | "En savoir plus" |
4.2. Props optionnelles
| Prop | Type | Description | Valeur par défaut |
|---|---|---|---|
variant |
'primary' | 'secondary' | 'outline' |
Style visuel du bouton | 'primary' |
size |
'sm' | 'md' | 'lg' |
Taille du bouton | 'md' |
disabled |
boolean |
État désactivé | false |
href |
string |
URL de redirection (rend le composant en <a>) |
undefined |
onClick |
() => void |
Callback au clic | undefined |
4.3. Slots (si applicable)
| Slot | Description | Obligatoire |
|---|---|---|
default |
Contenu personnalisé (remplace label) |
❌ |
icon |
Icône à afficher avant le label | ❌ |
5. Stratégie d’hydratation
5.1. Politique d’hydratation
| Type de composant | Stratégie | Rationale |
|---|---|---|
| Composants UI atomiques | Aucune | HTML + CSS purs, pas d’interaction |
| Navigation mobile | client:load |
Critique pour l’UX immédiate |
| Carrousel témoignages | client:visible |
Chargement différé (plus bas dans la page) |
| Formulaire de contact | client:load |
Interaction immédiate requise |
| Graphiques / Charts | client:visible |
Chargement différé |
5.2. Directives Astro utilisées
<!-- Aucune hydratation (HTML pur) --><Button label="Cliquez ici" />
<!-- Hydratation immédiate --><MobileNav client:load items={navItems} />
<!-- Hydratation au scroll (viewport) --><Carousel client:visible items={testimonials} />
<!-- Hydratation au repos (idle) --><Analytics client:idle />5.3. Impact sur les performances
| Métrique | Sans hydratation | Avec client:load |
Avec client:visible |
|---|---|---|---|
| HTML size | +2 KB | +2 KB | +2 KB |
| JS size | 0 KB | +15 KB | +15 KB (chargé plus tard) |
| TTI (Time to Interactive) | Immédiat | +50ms | +200ms (après scroll) |
| INP | N/A | Impacté | Impacté |
6. Styles et design system
6.1. Utilisation des design tokens
/* Le composant utilise les design tokens définis dans tokens.css */.button { background-color: var(--color-primary, #3b82f6); color: var(--color-text-inverse, #ffffff); padding: var(--spacing-md, 1rem) var(--spacing-lg, 1.5rem); border-radius: var(--radius-md, 0.5rem); font-family: var(--font-family-base, system-ui); font-size: var(--font-size-base, 1rem); font-weight: var(--font-weight-medium, 500); transition: background-color var(--transition-fast, 150ms) ease;}
.button:hover { background-color: var(--color-primary-dark, #2563eb);}
.button:focus-visible { outline: 2px solid var(--color-focus, #3b82f6); outline-offset: 2px;}6.2. Responsive design
/* Mobile-first approach */.button { width: 100%; padding: var(--spacing-sm, 0.75rem) var(--spacing-md, 1rem); font-size: var(--font-size-sm, 0.875rem);}
/* Tablet et desktop */@media (min-width: 768px) { .button { width: auto; padding: var(--spacing-md, 1rem) var(--spacing-lg, 1.5rem); font-size: var(--font-size-base, 1rem); }}6.3. Mode sombre (si applicable)
/* Support automatique via prefers-color-scheme */@media (prefers-color-scheme: dark) { .button { background-color: var(--color-primary-dark, #2563eb); }}
/* Ou via classe manuelle */[data-theme="dark"] .button { background-color: var(--color-primary-dark, #2563eb);}7. Accessibilité (a11y)
7.1. Conformité WCAG 2.1 AA1/2
| Critère | Implémentation | Statut |
|---|---|---|
| 1.1.1 Non-text Content | Attribut alt obligatoire pour les images |
✅ |
| 1.3.1 Info and Relationships | Structure HTML sémantique (<button>, <a>) |
✅ |
| 1.4.3 Contrast (Minimum) | Contraste texte/fond ≥ 4.5:1 | ✅ |
| 1.4.11 Non-text Contrast | Contraste éléments interactifs ≥ 3:1 | ✅ |
7.1. Conformité WCAG 2.1 AA2/2
| Critère | Implémentation | Statut |
|---|---|---|
| 2.1.1 Keyboard | Navigation clavier complète (Tab, Enter, Space) | ✅ |
| 2.1.2 No Keyboard Trap | Pas de piège au clavier | ✅ |
| 2.4.7 Focus Visible | Focus visible sur tous les éléments interactifs | ✅ |
| 4.1.2 Name, Role, Value | Attributs ARIA appropriés (aria-label, aria-expanded) |
✅ |
7.2. Attributs ARIA utilisés
<!-- Bouton --><button aria-label="Fermer la modale" aria-expanded="false" aria-controls="modal-content"> ×</button>
<!-- Carrousel --><div role="region" aria-label="Carrousel de témoignages" aria-roledescription="carousel"> <div role="group" aria-roledescription="slide" aria-label="1 sur 5" aria-hidden="false" > <!-- Contenu --> </div></div>
<!-- Navigation --><nav aria-label="Navigation principale"> <ul role="menubar"> <li role="none"> <a role="menuitem" href="/">Accueil</a> </li> </ul></nav>7.3. Navigation clavier
| Touche | Action |
|---|---|
Tab |
Navigation vers l’élément suivant |
Shift + Tab |
Navigation vers l’élément précédent |
Enter / Space |
Activation du bouton ou du lien |
Escape |
Fermeture de la modale ou du menu |
Flèches |
Navigation dans les menus / carrousels |
7.4. Tests d’accessibilité
# Test automatique avec axe-corenpx axe http://localhost:4321/
# Test avec Lighthousenpx lighthouse http://localhost:4321/ --view
# Test manuel# 1. Navigation complète au clavier (Tab, Shift+Tab)# 2. Vérification du focus visible# 3. Test avec un lecteur d'écran (VoiceOver, NVDA)# 4. Vérification du contraste avec WebAIM Contrast Checker8. Performance et optimisation
8.1. Optimisations appliquées
- ✅ HTML statique par défaut (pas de JavaScript sauf si nécessaire)
- ✅ CSS scoped (pas de fuite de styles)
- ✅ Images optimisées (WebP/AVIF via Cloudflare)
- ✅ Pas de JavaScript bloquant sur le chemin critique
- ✅ Lazy loading des composants interactifs (
client:visible)
8.2. Core Web Vitals
| Métrique | Objectif | Stratégie |
|---|---|---|
| LCP | < 2.5s | Images optimisées, pas de JS bloquant |
| INP | < 200ms | JavaScript minimal, îlots ciblés |
| CLS | < 0.1 | Dimensions explicites, pas de layout shift |
8.3. Taille du composant
| Type | HTML | CSS | JS (hydraté) | Total |
|---|---|---|---|---|
| UI atomique | 2 KB | 1 KB | 0 KB | 3 KB |
| Îlot interactif | 2 KB | 1 KB | 15 KB | 18 KB |
9. Débogage et troubleshooting
9.1. Problèmes courants
| Symptôme | Cause probable | Solution |
|---|---|---|
| Composant non visible | Import incorrect | Vérifier le chemin d’import |
| Styles cassés | Conflit CSS | Vérifier les spécificités et le scope |
| Hydratation ne fonctionne pas | Directive manquante | Ajouter client:load ou client:visible |
| Accessibilité dégradée | Structure HTML incorrecte | Valider avec axe-core |
| Performance dégradée | JavaScript inutile | Vérifier les hydratations |
| Focus invisible | CSS outline: none |
Retirer ou remplacer par focus-visible |
9.2. Tests manuels
# Test localnpm run dev
# Vérification de l'accessibiliténpx axe http://localhost:4321/
# Vérification des performancesnpx lighthouse http://localhost:4321/
# Test responsive# Utiliser les DevTools du navigateur (mode responsive)
# Test des interactions# Vérifier tous les états (hover, focus, active, disabled)9.3. Logs et monitoring
# Logs de développementnpm run dev
# Vérification des typesnpx astro check
# Analyse du bundlenpm run build -- --analyze10. Bonnes pratiques
10.1. Architecture
- ✅ Séparer les composants UI (atomiques) des composants interactifs (îlots)
- ✅ Utiliser les design tokens pour tous les styles (couleurs, spacing, typographie)
- ✅ Typer les props avec TypeScript
- ✅ Valider les props obligatoires
- ✅ Utiliser des valeurs par défaut pour les props optionnelles
10.2. Accessibilité
- ✅ Toujours utiliser des éléments HTML sémantiques (
<button>,<a>,<nav>) - ✅ Fournir des attributs ARIA appropriés
- ✅ Assurer une navigation clavier complète
- ✅ Vérifier le contraste (WCAG AA minimum)
- ✅ Tester avec un lecteur d’écran
10.3. Performance
- ✅ Éviter l’hydratation sauf si interaction requise
- ✅ Utiliser
client:visiblepour les composants bas de page - ✅ Optimiser les images (WebP/AVIF, dimensions explicites)
- ✅ Éviter le JavaScript bloquant sur le chemin critique
- ✅ Mesurer les Core Web Vitals régulièrement
10.4. Maintenance
- ✅ Documenter les props et slots dans ce fichier
- ✅ Créer des exemples d’utilisation
- ✅ Tester l’accessibilité régulièrement
- ✅ Vérifier les performances avec Lighthouse
- ✅ Mettre à jour les composants lors des changements de design
11. Évolutions et roadmap
11.1. Améliorations planifiées
- [Évolution 1 : ex. Support du mode sombre]
- [Évolution 2 : ex. Ajout de variantes de taille]
- [Évolution 3 : ex. Intégration d’animations]
11.2. Limitations connues
- ❌ Les composants UI ne peuvent pas avoir d’état (pas de JavaScript)
- ❌ Les îlots interactifs augmentent la taille du bundle JS
- ❌ L’hydratation
client:visiblenécessite l’Intersection Observer API
12. Ressources liées1/2
- Documentation Astro : Components
- Documentation Astro : Islands Architecture
- Documentation Astro : Client Directives
- DAT L2 : §4 - Stratégie d’Hydratation & Gestion du JavaScript
- DAT L2 : §11 - Accessibilité
12. Ressources liées2/2
- DAT L2 : §12 - Design System
- Composants associés :
src/components/ui/[ComposantParent].astrosrc/components/interactive/[ComposantEnfant].tsx
- Design tokens :
src/styles/tokens.css
13. Historique des modifications1/2
| Date | Version | Description | Auteur |
|---|---|---|---|
| YYYY-MM-DD | 1.0 | Création initiale | [Nom] |
| YYYY-MM-DD | 1.1 | [Modification] | [Nom] |
13. Historique des modifications2/2
---
**Points clés de ce template :**- Couvre les deux types de composants (UI atomique et îlot interactif)- Détaille la stratégie d'hydratation (critique pour les performances)- Inclut la conformité WCAG 2.1 AA (accessibilité)- Fournit l'intégration avec le design system (tokens CSS)- Sépare clairement les props, les slots, et les exemples d'utilisation- Inclut les bonnes pratiques de performance et de maintenance- Documente l'impact sur les Core Web Vitals