Communitygithub.com

Samueladewole/claude-skills

Créez des composants frontend accessibles, réactifs et performants en suivant les bonnes pratiques des systèmes de design, le CSS moderne et des patterns indépendants des frameworks.

Qu'est-ce que claude-skills ?

Cette compétence est conçue pour les designers et développeurs frontend souhaitant créer des interfaces utilisateur belles, accessibles et performantes. Elle couvre la conception et le développement de composants réutilisables, l'implémentation de systèmes de design complets (tokens, motifs, documentation), le design responsive mobile-first, l'accessibilité selon WCAG 2.1, le CSS moderne (Flexbox, Grid, propriétés personnalisées), l'optimisation des performances, les bonnes pratiques de frameworks comme React, Vue et Svelte, ainsi que le workflow de transformation du design en code (Figma vers production). Elle fournit des exemples concrets de composants (bouton, carte, champ de formulaire) avec leur code TypeScript et CSS, un système complet de tokens de design (couleurs, espacement, typographie, ombres), des motifs d'accessibilité (liens d'évitement, gestion du focus, labels ARIA), et des techniques CSS modernes (container queries, grilles adaptatives, thème clair/sombre). La compétence s'appuie sur des principes fondamentaux : accessibilité d'abord, mobile-first, performance par défaut, approche par composants (atomic design), et alignement sur un système de design. Elle inclut également des scripts utilitaires pour générer des composants, configurer un système de design ou auditer l'accessibilité. Cette compétence est indépendante du framework et peut être utilisée avec Claude Code, Cursor, Codex ou tout autre agent IA spécialisé dans le développement frontend.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/Samueladewole/claude-skills/tree/HEAD/frontend-designer

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Designer Frontend

Une compétence complète pour les designers et développeurs frontend afin de construire des interfaces utilisateur belles, accessibles et performantes avec les meilleures pratiques modernes.

Ce que fait cette compétence

Aide les designers/développeurs frontend avec :

  • Conception et développement de composants - Construire des composants réutilisables et accessibles
  • Systèmes de design - Implémenter des tokens, des motifs et de la documentation
  • Design responsive - Mise en page mobile-first et fluide
  • Accessibilité (WCAG 2.1) - Motifs de conception inclusifs
  • CSS moderne - Flexbox, Grid, propriétés personnalisées
  • Optimisation des performances - Frontends rapides et efficaces
  • Motifs de framework - Bonnes pratiques React, Vue, Svelte
  • Du design au code - Workflows Figma vers production

Pourquoi cette compétence est importante

Sans approche systématique :

  • Implémentations de composants incohérentes
  • Problèmes d'accessibilité
  • Mauvais comportement responsive
  • Code et styles dupliqués
  • Difficile à maintenir
  • Problèmes de performance

Avec cette compétence :

  • Composants cohérents et réutilisables
  • Conforme WCAG AA par défaut
  • Design responsive mobile-first
  • Aligné sur le système de design
  • Code maintenable
  • Livraison rapide et optimisée

Principes fondamentaux

1. Accessibilité d'abord

  • WCAG 2.1 AA minimum
  • HTML sémantique
  • Navigation au clavier
  • Support des lecteurs d'écran
  • Gestion du focus
  • Contraste des couleurs

2. Responsive mobile-first

  • Commencer par le mobile (320px)
  • Amélioration progressive
  • Typographie fluide
  • Mises en page flexibles
  • Cibles tactiles confortables

3. Performance par défaut

  • CSS/JS minimal
  • Chargement paresseux
  • Images optimisées
  • CSS critique
  • Tree shaking

4. Piloté par les composants

  • Méthodologie Atomic Design
  • Composants réutilisables
  • Personnalisation basée sur les props
  • Composition plutôt qu'héritage

5. Aligné sur le système de design

  • Tokens de design
  • Espacement cohérent
  • Échelle typographique
  • Palette de couleurs
  • Bibliothèque de composants

Motifs de composants

Composant Bouton

Motif de bouton accessible et flexible :

// Exemple React
interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  loading?: boolean;
  children: React.ReactNode;
  onClick?: () => void;
}

export const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  size = 'md',
  disabled = false,
  loading = false,
  children,
  onClick,
  ...props
}) => {
  return (
    <button
      className={`btn btn--${variant} btn--${size}`}
      disabled={disabled || loading}
      onClick={onClick}
      aria-busy={loading}
      {...props}
    >
      {loading ? <Spinner /> : children}
    </button>
  );
};

CSS (avec tokens de design) :

.btn {
  /* Styles de base */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);

  font-family: var(--font-sans);
  font-weight: 600;
  text-decoration: none;

  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;

  transition: all 0.2s ease;

  /* Accessibilité */
  min-height: 44px; /* Cible tactile WCAG */

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
}

/* Variantes */
.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);

  &:hover:not(:disabled) {
    background: var(--color-primary-hover);
  }
}

.btn--secondary {
  background: var(--color-secondary);
  color: var(--color-on-secondary);
}

.btn--ghost {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid currentColor;
}

/* Tailles */
.btn--sm {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.btn--md {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
}

.btn--lg {
  padding: var(--space-4) var(--space-6);
  font-size: var(--text-lg);
}

Composant Carte

Carte flexible et accessible :

interface CardProps {
  variant?: 'elevated' | 'outlined' | 'filled';
  padding?: 'none' | 'sm' | 'md' | 'lg';
  interactive?: boolean;
  children: React.ReactNode;
}

export const Card: React.FC<CardProps> = ({
  variant = 'elevated',
  padding = 'md',
  interactive = false,
  children,
}) => {
  const Component = interactive ? 'button' : 'div';

  return (
    <Component
      className={`
        card
        card--${variant}
        card--padding-${padding}
        ${interactive ? 'card--interactive' : ''}
      `}
      {...(interactive && { role: 'button', tabIndex: 0 })}
    >
      {children}
    </Component>
  );
};

CSS :

.card {
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.card--elevated {
  box-shadow: var(--shadow-md);
}

.card--outlined {
  border: 1px solid var(--color-border);
}

.card--filled {
  background: var(--color-surface-variant);
}

.card--interactive {
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;

  &:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
  }

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }
}

.card--padding-sm { padding: var(--space-3); }
.card--padding-md { padding: var(--space-4); }
.card--padding-lg { padding: var(--space-6); }

Composant Champ de Formulaire

Champ de formulaire accessible :

interface InputProps {
  label: string;
  error?: string;
  hint?: string;
  required?: boolean;
  type?: 'text' | 'email' | 'password' | 'number';
}

export const Input: React.FC<InputProps> = ({
  label,
  error,
  hint,
  required = false,
  type = 'text',
  ...props
}) => {
  const id = useId();
  const hintId = `${id}-hint`;
  const errorId = `${id}-error`;

  return (
    <div className="input-wrapper">
      <label htmlFor={id} className="input-label">
        {label}
        {required && <span aria-label="required">*</span>}
      </label>

      {hint && (
        <p id={hintId} className="input-hint">
          {hint}
        </p>
      )}

      <input
        id={id}
        type={type}
        className={`input ${error ? 'input--error' : ''}`}
        aria-required={required}
        aria-invalid={!!error}
        aria-describedby={error ? errorId : hint ? hintId : undefined}
        {...props}
      />

      {error && (
        <p id={errorId} className="input-error" role="alert">
          {error}
        </p>
      )}
    </div>
  );
};

Tokens de design

Propriétés personnalisées CSS pour le système de design :

:root {
  /* Couleurs - Primaire */
  --color-primary: #0066FF;
  --color-primary-hover: #0052CC;
  --color-on-primary: #FFFFFF;

  /* Couleurs - Surface */
  --color-surface: #FFFFFF;
  --color-surface-variant: #F5F5F5;
  --color-on-surface: #1A1A1A;

  /* Couleurs - Bordures */
  --color-border: #E0E0E0;
  --color-border-hover: #BDBDBD;

  /* Couleurs - Sémantique */
  --color-error: #D32F2F;
  --color-success: #388E3C;
  --color-warning: #F57C00;
  --color-info: #1976D2;

  /* Échelle d'espacement (base 8px) */
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-8: 3rem;     /* 48px */
  --space-10: 4rem;    /* 64px */

  /* Échelle typographique */
  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */
  --text-4xl: 2.25rem;   /* 36px */

  /* Familles de polices */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "SF Mono", Monaco, "Cascadia Code", monospace;

  /* Hauteurs de ligne */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* Rayons de bordure */
  --radius-sm: 0.25rem;  /* 4px */
  --radius-md: 0.5rem;   /* 8px */
  --radius-lg: 1rem;     /* 16px */
  --radius-full: 9999px;

  /* Ombres */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);

  /* Anneau de focus */
  --color-focus: #0066FF;

  /* Transitions */
  --transition-fast: 150ms ease;
  --transition-base: 200ms ease;
  --transition-slow: 300ms ease;
}

/* Mode sombre */
@media (prefers-color-scheme: dark) {
  :root {
    --color-surface: #1A1A1A;
    --color-surface-variant: #2A2A2A;
    --color-on-surface: #FFFFFF;
    --color-border: #3A3A3A;
  }
}

Motifs de design responsive

Points de rupture mobile-first

/* Approche mobile-first */
.container {
  padding: var(--space-4);

  /* Tablette : 768px et plus */
  @media (min-width: 48rem) {
    padding: var(--space-6);
  }

  /* Desktop : 1024px et plus */
  @media (min-width: 64rem) {
    padding: var(--space-8);
    max-width: 1200px;
    margin: 0 auto;
  }
}

Typographie fluide

/* Typographie responsive */
h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: var(--leading-tight);
}

h2 {
  font-size: clamp(1.5rem, 4vw, 2.5rem);
}

p {
  font-size: clamp(1rem, 2vw, 1.125rem);
  line-height: var(--leading-normal);
}

Mises en page en grille

/* Grille responsive */
.grid {
  display: grid;
  gap: var(--space-4);

  /* Colonnes auto-ajustées (min 280px) */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* Système de grille 12 colonnes */
.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-4);
}

.col-span-4 {
  grid-column: span 4;
}

/* Empiler sur mobile */
@media (max-width: 48rem) {
  .col-span-4 {
    grid-column: span 12;
  }
}

Motifs d'accessibilité

Liens d'évitement

export const SkipLink = () => (
  <a href="#main-content" className="skip-link">
    Aller au contenu principal
  </a>
);
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--color-primary);
  color: var(--color-on-primary);
  padding: var(--space-2) var(--space-4);
  text-decoration: none;
  z-index: 100;

  &:focus {
    top: 0;
  }
}

Gestion du focus

// Modale avec piège à focus
export const Modal = ({ isOpen, onClose, children }) => {
  const modalRef = useRef(null);

  useEffect(() => {
    if (isOpen) {
      // Sauvegarder l'élément actuellement focus
      const previouslyFocused = document.activeElement;

      // Focus le premier élément focusable dans la modale
      const firstFocusable = modalRef.current?.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      firstFocusable?.focus();

      // Restaurer le focus à la fermeture
      return () => previouslyFocused?.focus();
    }
  }, [isOpen]);

  if (!isOpen) return null;

  return (
    <div
      ref={modalRef}
      role="dialog"
      aria-modal="true"
      className="modal-overlay"
    >
      <div className="modal">
        {children}
      </div>
    </div>
  );
};

Labels ARIA

// Bouton icône avec label accessible
export const IconButton = ({ icon, label, ...props }) => (
  <button
    aria-label={label}
    className="icon-button"
    {...props}
  >
    <span aria-hidden="true">{icon}</span>
  </button>
);

// État de chargement
export const LoadingButton = ({ loading, children, ...props }) => (
  <button
    aria-busy={loading}
    aria-live="polite"
    disabled={loading}
    {...props}
  >
    {loading ? 'Chargement...' : children}
  </button>
);

Optimisation des performances

CSS critique

<!-- CSS critique en ligne -->
<style>
  /* Styles au-dessus de la ligne de flottaison */
  body { margin: 0; font-family: var(--font-sans); }
  .header { /* styles critiques de l'en-tête */ }
  .hero { /* styles critiques du héros */ }
</style>

<!-- Charger la feuille de style complète de manière asynchrone -->
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'">

Chargement paresseux des images

export const LazyImage = ({ src, alt, ...props }) => (
  <img
    src={src}
    alt={alt}
    loading="lazy"
    decoding="async"
    {...props}
  />
);

Découpage du code

// Chargement paresseux React
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Dashboard />
    </Suspense>
  );
}

Techniques CSS modernes

Container Queries

.card {
  container-type: inline-size;
}

.card-content {
  display: flex;
  flex-direction: column;

  /* Passer à une disposition en ligne lorsque le conteneur > 400px */
  @container (min-width: 400px) {
    flex-direction: row;
  }
}

Auto-fit de la grille CSS

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--space-4);
}

Propriétés personnalisées pour le thème

/* Thème clair (par défaut) */
:root {
  --bg: #ffffff;
  --text: #000000;
}

/* Thème sombre */
[data-theme="dark"] {
  --bg: #000000;
  --text: #ffffff;
}

body {
  background: var(--bg);
  color: var(--text);
}

Structure de la bibliothèque de composants

src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.css
│   │   ├── Button.test.tsx
│   │   └── Button.stories.tsx
│   ├── Card/
│   ├── Input/
│   └── index.ts
├── tokens/
│   ├── colors.css
│   ├── spacing.css
│   ├── typography.css
│   └── index.css
├── utils/
│   ├── a11y.ts
│   └── responsive.ts
└── index.ts

Utilisation de cette compétence

Générer un composant

./scripts/generate_component.sh Button

Crée un composant avec :

  • Fichier TypeScript/JSX
  • Module CSS
  • Fichier de test
  • Histoire Storybook
  • Vérifications d'accessibilité

Configuration du système de design

./scripts/setup_design_system.sh

Crée :

  • Tokens de design (propriétés personnalisées CSS)
  • Styles de base
  • Modèles de composants
  • Structure de documentation

Audit d'accessibilité

./scripts/audit_accessibility.sh

Vérifie :

  • Ratios de contraste des couleurs
  • Navigation au clavier
  • Attributs ARIA
  • HTML sémantique
  • Gestion du focus

Meilleures pratiques

Conception de composants

✅ À FAIRE :

  • Utiliser du HTML sémantique
  • Rendre les composants accessibles au clavier
  • Fournir des labels ARIA
  • Prendre en charge les modes clair et sombre

❌ À ÉVITER :

  • Composants sans accessibilité
  • Tailles fixes (px) au lieu d'unités relatives
  • Balises <div> au lieu d'éléments sémantiques
  • Ignorer la gestion du focus
  • État de chargement manquant pour les actions asynchrones

Accessibilité

Contraste des couleurs :

  • Texte normal : ratio de contraste 4.5:1 minimum
  • Grand texte (18px+ ou 14px en gras) : ratio 3:1
  • Composants d'interface utilisateur : ratio 3:1

Navigation au clavier :

  • Tous les éléments interactifs doivent être accessibles au clavier
  • Ordre de tabulation logique
  • Indicateurs de focus visibles
  • Pas de piège à focus

Lecteurs d'écran :

  • Utiliser aria-label pour les boutons icône
  • aria-live pour les mises à jour dynamiques
  • aria-expanded pour les sections dépliables
  • role="alert" pour les messages d'erreur

Performance

Optimisations CSS :

  • Minimiser la spécificité des sélecteurs
  • Utiliser des propriétés personnalisées pour les couleurs et l'espacement
  • Éviter @import pour le chargement des feuilles de style
  • Utiliser will-change avec parcimonie

Optimisations JavaScript :

  • Découpage du code avec React.lazy()
  • Mémoïsation des composants coûteux
  • Chargement paresseux des images et des iframes
  • Éviter les re-rendus inutiles

Exemples supplémentaires

Barre de navigation avec navigation clavier

export const NavigationBar: React.FC = () => {
  const navRef = useRef<HTMLElement>(null);

  return (
    <nav ref={navRef} aria-label="Navigation principale">
      <ul className="nav-list">
        <li><a href="/" className="nav-link">Accueil</a></li>
        <li><a href="/about" className="nav-link">À propos</a></li>
        <li><a href="/contact" className="nav-link">Contact</a></li>
      </ul>
    </nav>
  );
};
.nav-list {
  display: flex;
  list-style: none;
  gap: var(--space-4);
  padding: 0;
  margin: 0;
}

.nav-link {
  text-decoration: none;
  color: var(--color-on-surface);
  font-weight: 500;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  transition: background 0.2s;

  &:hover {
    background: var(--color-surface-variant);
  }

  &:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
  }
}

Toast de notification accessible

interface ToastProps {
  message: string;
  type: 'success' | 'error' | 'info';
  onClose: () => void;
}

export const Toast: React.FC<ToastProps> = ({ message, type, onClose }) => {
  return (
    <div
      className={`toast toast--${type}`}
      role="alert"
      aria-live="assertive"
    >
      <p className="toast-message">{message}</p>
      <button
        onClick={onClose}
        className="toast-close"
        aria-label="Fermer la notification"
      >
        ×
      </button>
    </div>
  );
};
.toast {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  color: white;
}

.toast--success {
  background: var(--color-success);
}

.toast--error {
  background: var(--color-error);
}

.toast--info {
  background: var(--color-info);
}

.toast-close {
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
}

Contribution

Cette compétence est ouverte aux améliorations. Les contributions sont les bienvenues :

  • Signaler des bugs d'accessibilité
  • Suggérer des motifs de composants
  • Ajouter des exemples spécifiques à un framework
  • Améliorer la documentation

Licence

MIT


Construit avec des bonnes pratiques d'accessibilité, de design responsive et de performance.

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

Samueladewole/claude-skills

Create API handoff documentation for frontend developers. Use when backend work is complete and needs to be documented for frontend integration, or user says 'create handoff', 'document API', 'frontend handoff', or 'API documentation'.

Samueladewole/claude-skills

Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling

Samueladewole/claude-skills

Document frontend data needs for backend developers. Use when frontend needs to communicate API requirements to backend, or user says 'backend requirements', 'what data do I need', 'API requirements', or is describing data needs for a UI.

Samueladewole/claude-skills

Master Next.js 14+ App Router with Server Components, streaming, parallel routes, and advanced data fetching. Use when building Next.js applications, implementing SSR/SSG, or optimizing React Server Components.

Samueladewole/claude-skills

Analyze a short-form video (TikTok, Instagram Reel, YouTube Short, or any MP4) to extract its full transcript, understand why it performed, and generate concrete repurposing ideas. Use this skill whenever the user asks to: analyze a video, understand why something went viral, reverse-engineer a creator's content, extract a transcript from a video, figure out what makes a video perform, or get repurposing ideas from a video. Also trigger when the user says things like "why did this perform", "what's the hook here", "can I repurpose this", "analyze this TikTok/Reel", or drops a video file path or URL.

Skills associés