💻 Développement

dev-react-component-builder

Crée des composants React/Vue/Angular/Svelte optimisés et réutilisables.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-react-component-builder --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-react-component-builder -Launch"

🚀 Déjà installé ?

claude "/dev-react-component-builder"

Ou tapez /dev-react-component-builder dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

composant ReactcomponentVue componentAngular componentSveltehooksstate managementcréer un composant

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-react-component-builder ~/.claude/skills/

Payload du plugin : skills/dev-react-component-builder · source éditable : dev-skills/react-component-builder

📖 Manuel

React Component Builder

Workflow

1. Cadrage rapide

Avant de coder, confirmer :

2. Design de l'API publique

Définir l'interface TypeScript avant toute implémentation.

// React — props typées avec valeurs par défaut
interface ButtonProps {
  label: string;
  variant?: 'primary' | 'secondary' | 'danger';
  disabled?: boolean;
  loading?: boolean;
  onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
  className?: string;
}

const Button = ({
  label,
  variant = 'primary',
  disabled = false,
  loading = false,
  onClick,
  className,
}: ButtonProps) => { /* ... */ };

Critères de décision — quoi exposer :

3. Choix du pattern d'architecture

Cas d'usagePattern recommandé
Composant simple, état localComposant fonctionnel + hooks
Composant avec sous-parties coupléesCompound components (<Select><Option>)
Logique réutilisable cross-composantsCustom hook
Inversion de contrôle sur le renduRender props / slot
Composant wrapper transparentforwardRef + useImperativeHandle
// Compound components — exemple Select
const Select = ({ children, onChange }: SelectProps) => {
  const [value, setValue] = useState('');
  return (
    <SelectContext.Provider value={{ value, onChange: setValue }}>
      <div role="listbox">{children}</div>
    </SelectContext.Provider>
  );
};
Select.Option = SelectOption; // sous-composant attaché

4. State management — où vivre l'état

État local uniquement → useState / useReducer
Partage parent→enfants proches → props drilling (acceptable jusqu'à 2 niveaux)
Partage dans un sous-arbre → Context API + useContext
État global UI (modales, thème) → Zustand (React) / Pinia (Vue) / NgRx (Angular)
État serveur → React Query / SWR / Apollo (jamais dans un store global)
// Zustand — slice minimal
import { create } from 'zustand';

interface ModalStore {
  isOpen: boolean;
  open: () => void;
  close: () => void;
}

export const useModalStore = create<ModalStore>((set) => ({
  isOpen: false,
  open: () => set({ isOpen: true }),
  close: () => set({ isOpen: false }),
}));

5. Styling — choix adapté au projet

// CSS Modules (isolation, zéro runtime)
import styles from './Button.module.css';
<button className={`${styles.btn} ${styles[variant]}`}>{label}</button>

// Tailwind (utilitaire, tree-shaking natif)
const variantClass = { primary: 'bg-blue-600', secondary: 'bg-gray-200' }[variant];
<button className={`px-4 py-2 rounded ${variantClass} ${className ?? ''}`}>{label}</button>

// clsx pour conditions complexes (toujours préférer à template literals)
import clsx from 'clsx';
<button className={clsx('px-4 py-2', { 'opacity-50 cursor-not-allowed': disabled }, variantClass)}>

6. Accessibilité — non négociable

Checklist systématique :

// Dialogue accessible
const Dialog = ({ title, onClose, children }: DialogProps) => {
  const closeRef = useRef<HTMLButtonElement>(null);
  useEffect(() => { closeRef.current?.focus(); }, []);

  return (
    <div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
      <h2 id="dialog-title">{title}</h2>
      {children}
      <button ref={closeRef} onClick={onClose} aria-label="Fermer">✕</button>
    </div>
  );
};

7. Tests avec React Testing Library

// Tester le comportement, pas l'implémentation
import { render, screen, userEvent } from '@testing-library/react';

test('appelle onClick avec le bon argument', async () => {
  const handleClick = vi.fn();
  render(<Button label="Valider" onClick={handleClick} />);
  await userEvent.click(screen.getByRole('button', { name: 'Valider' }));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

test('bouton disabled ne déclenche pas onClick', async () => {
  const handleClick = vi.fn();
  render(<Button label="Valider" disabled onClick={handleClick} />);
  await userEvent.click(screen.getByRole('button'));
  expect(handleClick).not.toHaveBeenCalled();
});

Sélecteurs par priorité (RTL) : getByRole > getByLabelText > getByText > getByTestId (dernier recours).

8. Story Storybook

// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  component: Button,
  args: { label: 'Cliquer', variant: 'primary' },
};
export default meta;

export const Primary: StoryObj<typeof Button> = {};
export const Loading: StoryObj<typeof Button> = { args: { loading: true } };
export const Disabled: StoryObj<typeof Button> = { args: { disabled: true } };

Anti-patterns / Pièges

Bonnes pratiques 2026