FlowingDev

Le SVG dans React : de l''image statique au composant dynamique

Apprenez à transformer des images SVG statiques en composants React (JSX/TSX) dynamiques et réutilisables qui peuvent accepter des props, changer de couleur, et bien plus.

Essayer l'outil: SVG vers JSX

En une phrase

SVG vers JSX transforme le code de votre image vectorielle en un composant React réutilisable, le rendant dynamique et contrôlable avec des props au lieu d'être un simple fichier statique.

Le problème que ça résout

Au bon vieux temps du web (genre, il y a cinq ans), si vous vouliez afficher une icône SVG, vous l'auriez probablement balancée dans une balise <img> : <img src="/icons/user.svg" alt="User profile" />. Et voilà le travail. On met en prod.

Mais cette approche simpliste est un peu un piège. Votre SVG est désormais une boîte noire. Vous voulez changer sa couleur quand l'utilisateur survole le bouton qui la contient ? Pas de bol. Le navigateur la traite comme n'importe quel autre fichier image (un JPG, un PNG), et vous ne pouvez pas facilement styler ses entrailles avec du CSS. Animer un des tracés à l'intérieur de l'icône ? Nope. Changer sa couleur pour un thème sombre ? Vous allez devoir créer un tout nouveau fichier (user-white.svg) et écrire de la logique pour intervertir le src. Ça devient vite le bazar.

« Aha ! » se dit le développeur malin. « Le SVG, c'est juste du balisage XML ! Je n'ai qu'à copier le code du fichier .svg et le coller directement dans le return de mon composant ! »

// MyComponent.js
const MyComponent = () => (
  <div>
    <p>My Profile</p>
    {/* I just pasted this from a .svg file! */}
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M12 12C14.21 12 16 10.21 16 8C16 5.79 14.21 4 12 4C9.79 4 8 5.79 8 8C8 10.21 9.79 12 12 12ZM12 14C9.33 14 4 15.34 4 18V20H20V18C20 15.34 14.67 14 12 14Z" fill="black"/>
    </svg>
  </div>
);

C'est ce qu'on appelle l'« inlining » (ou l'intégration en ligne), et c'est un grand pas en avant. Maintenant, le SVG fait partie du DOM, et vous pouvez le styler en CSS. Mais vous avez juste échangé un problème contre un autre.

  1. C'est lourdingue : Ce pavé de code SVG rend votre composant plus difficile à lire. Imaginez si vous aviez cinq icônes dedans.
  2. Ce n'est pas réutilisable : Besoin de cette icône utilisateur ailleurs ? Préparez-vous à copier-coller ce pavé de code partout.
  3. Ce n'est pas du JSX : React a son propre dialecte de HTML. Les attributs comme stroke-width doivent être en camelCase (strokeWidth), et class devient className. Oublier de les convertir peut entraîner des erreurs silencieuses ou des avertissements bien bruyants dans la console.

La vraie solution, c'est de traiter les icônes non pas comme des assets statiques, mais comme des citoyens de première classe de votre écosystème de composants. Ce que vous voulez, c'est <UserIcon color="blue" size={24} />. C'est le problème que la conversion SVG vers JSX résout : elle automatise le code répétitif (le boilerplate) pour transformer du balisage SVG brut en un composant React propre, réutilisable et piloté par les props.

Comment ça marche sous le capot

Transformer un bloc de texte en un composant React bien propre peut sembler magique, mais c'est un processus prévisible, étape par étape. Soulevons le rideau.

Étape 1 : Parser le balisage SVG

D'abord, l'outil doit comprendre le SVG. Comme le SVG est un dialecte du XML, il peut être « parsé » (analysé) en une structure en arbre de nœuds, tout comme un document HTML. Chaque élément (<svg>, <path>, <g>, etc.) devient un nœud, et ses attributs (width, fill, d, etc.) deviennent des propriétés de ce nœud.

Donc, ceci :

<svg width="24" height="24">
  <path fill-rule="evenodd" d="..." />
</svg>

Est compris par le parser comme un arbre :

  • nœud svg avec les attributs width="24" et height="24"
    • nœud path avec les attributs fill-rule="evenodd" et d="..."

Étape 2 : La « JSX-ification » des attributs

C'est là que la traduction spécifique à React se produit. Le parser parcourt l'arbre de nœuds et convertit les attributs pour qu'ils soient conformes au JSX.

  • Passage en camelCase : Tout attribut avec un tiret (en kebab-case) est converti en camelCase. fill-rule devient fillRule, stroke-width devient strokeWidth.
  • Mapping des mots-clés : Les mots-clés réservés de JavaScript sont remplacés. Le plus courant est class, qui devient className.
  • Attributs de style : Un attribut style="fill:red; stroke:blue" est converti en un objet JavaScript : style={{ fill: 'red', stroke: 'blue' }}.

Ainsi, <path fill-rule="evenodd" class="icon-path"> se transforme en son équivalent JSX : <path fillRule="evenodd" className="icon-path">.

Étape 3 : L'encapsulation dans un composant

Maintenant que l'arbre SVG parle couramment le JSX, l'étape suivante consiste à l'envelopper dans la structure standard d'un composant fonctionnel React. La version la plus simple ressemble à ça :

import React from 'react';

const MyIcon = () => {
  return (
    <svg width="24" height="24" viewBox="0 0 24 24">
      {/* ... tous les tracés et autres éléments "JSX-ifiés" ... */}
    </svg>
  );
};

export default MyIcon;

Cela vous donne déjà un composant réutilisable <MyIcon />, ce qui est une belle victoire. Mais la vraie puissance vient du fait de le rendre dynamique.

Étape 4 : Ajout des props et de currentColor

C'est l'ingrédient secret. Un bon convertisseur ne se contente pas de coder en dur les attributs d'origine du SVG. Il les rend configurables.

  • Le « spread » des props : Le composant est modifié pour accepter des props et les « étaler » (spread) sur l'élément <svg> racine. C'est souvent fait avec la syntaxe ...rest. Vous pouvez maintenant passer n'importe quel attribut SVG standard (comme width, height, className ou aria-label) directement à votre composant.

  • L'astuce currentColor : Ça, ça change la donne pour le style. Le convertisseur va trouver les attributs fill et stroke codés en dur qui définissent la couleur de l'icône (ex: fill="#000000") et les remplacer par le mot-clé CSS spécial currentColor.

currentColor dit au navigateur : « Quelle que soit la propriété CSS color sur cet élément, utilise-la pour le fill/stroke. » Cela signifie que votre icône se comporte désormais comme du texte. Si vous enveloppez votre icône dans une div et que vous définissez color: blue, l'icône devient bleue.

// Le composant amélioré
const MyIcon = ({ color = 'currentColor', size = 24, ...rest }) => {
  return (
    <svg 
      width={size} 
      height={size} 
      fill={color} // ou appliqué directement aux tracés
      {...rest}
    >
      <path d="..." fill="currentColor" />
    </svg>
  );
};

Étape 5 : Transférer les refs (Forwarding Refs)

Parfois, vous avez besoin d'obtenir une référence directe sur l'élément DOM <svg> réel depuis un composant parent, peut-être pour mesurer sa position ou l'utiliser avec une librairie tierce. Un composant fonctionnel normal cache sa structure DOM interne. La solution est React.forwardRef.

Un convertisseur sophistiqué enveloppera le composant dans React.forwardRef, qui crée un conduit pour passer une ref du parent directement à la balise <svg> sous-jacente.

Le composant final, prêt pour la prod, ressemble souvent à quelque chose comme ça (exemple en TypeScript) :

import * as React from 'react';

type Props = React.SVGProps<SVGSVGElement>;

const MyIcon = React.forwardRef<SVGSVGElement, Props>((props, ref) => (
  <svg ref={ref} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
    <path d="..." fill="currentColor" />
  </svg>
));

MyIcon.displayName = 'MyIcon'; // Pratique pour le débogage
export default MyIcon;

Histoires vécues

Le cauchemar du theming

Une équipe front-end construisait une superbe application web avec un mode clair et un mode sombre. Ils utilisaient une cinquantaine d'icônes, toutes implémentées avec <img src="/icons/whatever.svg">. Les icônes étaient noires. Quand ils ont mis en ligne le mode sombre, la panique s'est installée : les 50 icônes noires ont disparu sur le nouveau fond sombre. Leur premier « correctif » paniqué a été d'exporter un deuxième jeu d'icônes blanches (whatever-dark.svg) et d'écrire partout une logique conditionnelle bien dégueu (isDarkMode ? 'whatever-dark.svg' : 'whatever.svg'). C'était un enfer à maintenir.

Puis, un développeur a introduit un workflow de conversion SVG vers JSX. Ils ont lancé un script qui a converti les 50 SVG en composants React, en remplaçant de manière cruciale tous les attributs fill="black" par fill="currentColor". Ils ont remplacé toutes les balises <img> par leurs nouveaux composants d'icônes, comme <WhateverIcon />. Instantanément, les icônes ont hérité de la couleur de leur texte parent, qui était déjà gérée par le CSS du thème. Mode clair : texte noir, icônes noires. Mode sombre : texte blanc, icônes blanches. Ça a juste marché.

Leçon : Intégrer les SVG en tant que composants leur permet de s'intégrer de manière transparente avec le design system et le style existants de votre application, vous évitant ainsi l'enfer de la gestion d'assets.

La coche animée

Un product manager voulait une animation « charmante » : lorsqu'un utilisateur remplit un formulaire, une coche doit se dessiner dynamiquement à l'écran. Utiliser un GIF animé était hors de question — l'image était pixelisée et le fichier lourd. La développeuse a essayé de trouver une librairie, mais rien ne correspondait vraiment au design personnalisé de la coche.

Prenant les choses en main, elle a pris le SVG statique de la coche fourni par le designer et l'a converti en composant JSX. Cela lui a donné un accès direct à l'élément <path> de la coche dans son code React. En utilisant une simple transition CSS sur les propriétés stroke-dasharray et stroke-dashoffset de ce tracé, elle a pu créer l'effet de « dessin » exact qu'elle voulait. L'animation était parfaitement fluide, scalable à l'infini et ne pesait moins de 1 Ko de code.

Leçon : Convertir un SVG en composant débloque un contrôle granulaire sur ses parties individuelles, rendant possibles des animations complexes pilotées par CSS ou JavaScript.

Erreurs et pièges courants

  • Oublier l'accessibilité. Une icône qui a un sens (comme un X pour « fermer ») n'est pas juste une décoration. Si vous supprimez la balise <title> lors de la conversion, un lecteur d'écran pourrait l'annoncer comme « groupe » ou simplement l'ignorer. Assurez-vous toujours que votre composant final ait une prop aria-label appropriée ou un nom accessible via un élément <title> à l'intérieur du SVG. Un bon composant sera rendu comme <svg role="img" ...>.
  • Gonfler le bundle. Intégrer des SVG signifie que leur code fait maintenant partie de votre bundle JavaScript. Pour quelques dizaines de petites icônes d'UI, c'est un gain net (moins de requêtes HTTP). Mais si vous essayez d'intégrer une illustration énorme et complexe avec des milliers de tracés, vous pouvez sérieusement gonfler la taille de votre bundle et ralentir le chargement initial de la page. Pour les grandes illustrations statiques, <img> reste un choix parfaitement valide.
  • Ignorer l'optimisation en amont. Les SVG exportés depuis des outils de design comme Figma ou Adobe Illustrator sont notoirement bordéliques. Ils contiennent des métadonnées de l'éditeur, des commentaires, des calques cachés et des valeurs décimales trop précises. Balancer ça directement dans un composant JSX donne un code lourd et difficile à lire. Passez toujours vos SVG dans un optimiseur comme SVGO avant de les convertir. Cela peut souvent réduire la taille du code de 50 % ou plus.
  • L'édition manuelle devient un problème de synchro. Vous convertissez icon.svg en Icon.jsx. Puis vous modifiez manuellement Icon.jsx pour ajouter une fonctionnalité. Une semaine plus tard, le designer vous donne une version mise à jour de icon.svg. Vous avez maintenant le choix : relancer la conversion et perdre vos modifications manuelles, ou essayer de patcher manuellement le nouveau design dans votre JSX modifié. La source de vérité devrait être le fichier .svg ; la conversion en JSX devrait être un script répétable et automatisé.

Pourquoi vous devriez garder ça à l'œil

Vous devriez envisager de convertir les SVG en JSX chaque fois que vous construisez une application web à base de composants (React, Preact, etc.) et que vos icônes doivent être plus que de simples images statiques.

C'est le bon outil pour le travail quand :

  • Vous avez besoin que les icônes changent de couleur, de taille ou d'épaisseur de trait en fonction de l'état ou des props.
  • Vous construisez un design system ou une bibliothèque de composants et avez besoin d'un moyen scalable et cohérent de gérer les icônes.
  • Vous voulez animer des parties d'une icône.
  • Vous optimisez les performances et voulez réduire le nombre de requêtes réseau en intégrant (inlining) les icônes critiques.

Dans le développement frontend moderne, traiter vos icônes comme des composants n'est pas un hack — c'est la norme pour construire des interfaces utilisateur dynamiques, maintenables et performantes.

Pour aller plus loin

Théorie bouclée. Place à la pratique — 100 % dans ton navigateur.

Essayer l'outil: SVG vers JSX