Skip to content

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]
Slice : [Numéro de la tranche verticale]
Version : 1.0


[Description concise du rîle de ce composant dans l’interface utilisateur]

  • [Objectif principal : ex. afficher un bouton d’action rĂ©utilisable]
  • [BĂ©nĂ©fice pour l’UX ou l’architecture]
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]

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].tsx
Composant parent Fichier Relation
[Nom du parent] src/components/[chemin] [Composition / Wrapper]
Composant enfant Fichier RĂŽle
[Nom de l’enfant] src/components/[chemin] [Description]

3.1. Variante : Composant UI atomique (HTML + CSS purs)

Section titled “3.1. Variante : Composant UI atomique (HTML + CSS purs)”
src/components/ui/[NomComposant].astro
---
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>
)}
src/components/interactive/[NomComposant].tsx
import { useState } from 'react';
interface Props {
initialValue?: number;
}
export default function Counter({ initialValue = 0 }: Props) {
const [count, setCount] = useState(initialValue);
return (
<div class="flex items-center gap-4">
<button onClick={() => setCount(c => c - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}

Prop Type Obligatoire Validation
label string ✅ Non vide
variant enum ❌ Valeur par dĂ©faut
size enum ❌ Valeur par dĂ©faut
ÉlĂ©ment Type Description
HTML HTMLElement Composant rendu
ÉvĂ©nements Event onClick, onChange, etc.
État Type Description
count number Valeur du compteur

Scénario Description Résultat attendu
Rendu avec props Props valides Composant rendu correctement
Accessibilité Test ARIA Conforme WCAG AA
Responsive Test mobile/desktop Adaptation correcte
Scénario Dépendances Description Résultat attendu
Intégration parent Composant parent Utilisation dans une page Fonctionne correctement
Scénario Parcours utilisateur Description Résultat attendu
Interaction utilisateur Clic / Interaction Action utilisateur Réponse attendue

Composant Type RĂŽle MĂ©thode d’intĂ©gration
Page parent L2 Utilisation du composant Import et rendu
Layout L2 Inclusion globale Import dans layout
  • Les props doivent ĂȘtre typĂ©es avec TypeScript
  • L’accessibilitĂ© doit ĂȘtre conforme WCAG AA
  • Le composant doit ĂȘtre responsive
  • Le composant fonctionne en isolation
  • Le composant s’intĂšgre correctement avec les parents
  • Les tests d’accessibilitĂ© passent
  • Les tests E2E passent

  • ✅ Validation des props
  • ✅ Protection XSS (Astro par dĂ©faut)
  • ✅ Sanitization du contenu utilisateur
  • ✅ Ne jamais exĂ©cuter de code utilisateur non sĂ©curisĂ©
  • ✅ Valider toutes les entrĂ©es
  • ✅ Utiliser les attributs ARIA appropriĂ©s

Directive Description
client:load Hydratation immédiate
client:visible Hydratation quand visible
client:idle Hydratation quand le navigateur est inactif
  • ❌ Les Ăźlots interactifs augmentent le bundle size
  • ❌ L’hydratation peut affecter le LCP

SymptĂŽme Cause probable Solution
Composant non rendu Props manquantes Vérifier les props
Hydratation échoue Erreur JavaScript Vérifier la console
Accessibilité échoue ARIA manquant Ajouter les attributs
Terminal window
# Lancer les tests
npm run test
# Lancer les tests E2E
npm run test:e2e

  • ✅ Composants atomiques rĂ©utilisables
  • ✅ Props typĂ©es avec TypeScript
  • ✅ AccessibilitĂ© par dĂ©faut
  • ✅ Utiliser les classes Tailwind pour le style
  • ✅ Éviter les effets de bord
  • ✅ Documenter les props complexes
  • ✅ Documenter les changements dans ce fichier
  • ✅ Tester les modifications en local

  • [Évolution 1]
  • [Évolution 2]
  • ❌ [Limitation 1]
  • ❌ [Limitation 2]

  • Documentation Astro : Components
  • Documentation Astro : Islands
  • DAT L2 : §5.4 - StratĂ©gie d’Hydratation

Date Version Description Auteur
YYYY-MM-DD 1.0 Création initiale [Nom]
Edit page

Last updated: