FlowingDev

SVG in React: Vom statischen Bild zur dynamischen Komponente

Lerne, wie du statische SVG-Bilder in dynamische, wiederverwendbare React-Komponenten (JSX/TSX) umwandelst, die Props annehmen, Farben ändern und mehr können.

Tool ausprobieren: SVG zu JSX

In einem Satz

SVG zu JSX verwandelt den Code deines Vektorbildes in eine wiederverwendbare React-Komponente. Dadurch wird es dynamisch und mit Props steuerbar, anstatt nur eine statische Datei zu sein.

Welches Problem es löst

In den guten alten Zeiten des Webs (also so vor fünf Jahren), wenn du ein SVG-Icon anzeigen wolltest, hast du es wahrscheinlich einfach in einen <img>-Tag geklatscht: <img src="/icons/user.svg" alt="User profile" />. Job erledigt. Ab dafür.

Aber dieser simple Ansatz ist eine kleine Falle. Dein SVG ist jetzt eine Blackbox. Willst du die Farbe ändern, wenn der User mit der Maus über den Button fährt? Pech gehabt. Der Browser behandelt es wie jede andere Bilddatei (ein JPG, ein PNG), und du kannst seine Innereien nicht einfach mit CSS stylen. Einen der Pfade im Icon animieren? Nö. Die Farbe für ein Dark-Mode-Theme wechseln? Dann musst du eine komplett neue Datei (user-white.svg) erstellen und Logik schreiben, um das src-Attribut auszutauschen. Das wird schnell unübersichtlich.

„Aha!“, sagt der clevere Entwickler. „SVG ist doch nur XML-Markup! Ich kopiere einfach den Code aus der .svg-Datei und füge ihn direkt in das return-Statement meiner Komponente ein!“

// 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>
);

Das nennt man „Inlining“ und es ist ein riesiger Fortschritt. Jetzt ist das SVG Teil des DOM, und du kannst es mit CSS stylen. Aber du hast nur ein Problem gegen ein anderes eingetauscht.

  1. Es ist klobig: Dieser Batzen SVG-Code macht deine Komponente schwerer lesbar. Stell dir vor, du hättest fünf Icons da drin.
  2. Es ist nicht wiederverwendbar: Brauchst du das User-Icon woanders? Mach dich bereit, den ganzen Batzen immer wieder zu kopieren und einzufügen.
  3. Es ist kein JSX: React hat seinen eigenen HTML-Dialekt. Attribute wie stroke-width müssen in camelCase (strokeWidth) umgewandelt werden, und class wird zu className. Wenn du vergisst, das zu konvertieren, kann das zu stillen Fehlern oder lauten Warnungen in der Konsole führen.

Die wahre Lösung ist, Icons nicht als statische Assets zu behandeln, sondern als vollwertige Bürger deines Komponenten-Ökosystems. Du willst <UserIcon color="blue" size={24} />. Das ist das Problem, das die SVG-zu-JSX-Konvertierung löst: Sie automatisiert den Boilerplate-Code, um rohes SVG-Markup in eine saubere, wiederverwendbare und prop-gesteuerte React-Komponente zu verwandeln.

Wie es unter der Haube funktioniert

Einen Textbatzen in eine schicke React-Komponente zu verwandeln, mag wie Magie aussehen, ist aber ein vorhersagbarer, schrittweiser Prozess. Werfen wir mal einen Blick hinter den Vorhang.

Schritt 1: Parsen des SVG-Markups

Zuerst muss das Tool das SVG verstehen. Da SVG ein XML-Dialekt ist, kann es wie ein HTML-Dokument in eine Baumstruktur aus Knoten (Nodes) geparst werden. Jedes Element (<svg>, <path>, <g>, usw.) wird zu einem Node, und seine Attribute (width, fill, d, usw.) werden zu Eigenschaften dieses Nodes.

Also, das hier:

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

Wird vom Parser als Baum verstanden:

  • svg-Node mit den Attributen width="24" und height="24"
    • path-Node mit den Attributen fill-rule="evenodd" und d="..."

Schritt 2: JSX-ifizieren der Attribute

Hier findet die React-spezifische Übersetzung statt. Der Parser durchläuft den Node-Baum und konvertiert die Attribute, damit sie JSX-kompatibel sind.

  • Camel-casing: Jedes Attribut mit einem Bindestrich (kebab-case) wird in camelCase umgewandelt. fill-rule wird zu fillRule, stroke-width zu strokeWidth.
  • Keyword-Mapping: Reservierte JavaScript-Schlüsselwörter werden ausgetauscht. Das häufigste ist class, das zu className wird.
  • Style-Attribute: Ein style="fill:red; stroke:blue"-Attribut wird in ein JavaScript-Objekt umgewandelt: style={{ fill: 'red', stroke: 'blue' }}.

Also wird aus <path fill-rule="evenodd" class="icon-path"> das JSX-Äquivalent: <path fillRule="evenodd" className="icon-path">.

Schritt 3: In eine Komponente verpacken

Nachdem der SVG-Baum nun fließend JSX spricht, ist der nächste Schritt, ihn in die Struktur einer standardmäßigen funktionalen React-Komponente zu packen. Die einfachste Version sieht so aus:

import React from 'react';

const MyIcon = () => {
  return (
    <svg width="24" height="24" viewBox="0 0 24 24">
      {/* ... all the JSX-ified paths and other elements ... */}
    </svg>
  );
};

export default MyIcon;

Das gibt dir bereits eine wiederverwendbare <MyIcon />-Komponente, was ein großer Gewinn ist. Aber die wahre Stärke liegt darin, sie dynamisch zu machen.

Schritt 4: Hinzufügen von Props und currentColor

Das ist die geheime Zutat. Ein guter Konverter hardcodiert nicht einfach die ursprünglichen Attribute des SVGs. Er macht sie konfigurierbar.

  • Props verteilen (Spreading): Die Komponente wird so modifiziert, dass sie Props entgegennimmt und diese auf das root-<svg>-Element verteilt. Das wird oft mit der ...rest-Syntax gemacht. Jetzt kannst du jedes Standard-SVG-Attribut (wie width, height, className oder aria-label) direkt an deine Komponente übergeben.

  • Der currentColor-Trick: Das ist ein Game-Changer für's Styling. Der Konverter findet hartcodierte fill- und stroke-Attribute, die die Farbe des Icons definieren (z. B. fill="#000000"), und ersetzt sie durch das spezielle CSS-Keyword currentColor.

currentColor sagt dem Browser: „Welchen Wert auch immer die CSS-Eigenschaft color auf diesem Element hat, benutze ihn für fill oder stroke." Das bedeutet, dein Icon verhält sich jetzt wie Text. Wenn du dein Icon in ein Div packst und color: blue setzt, wird das Icon blau.

// Die verbesserte Komponente
const MyIcon = ({ color = 'currentColor', size = 24, ...rest }) => {
  return (
    <svg 
      width={size} 
      height={size} 
      fill={color} // oder direkt auf die Pfade angewendet
      {...rest}
    >
      <path d="..." fill="currentColor" />
    </svg>
  );
};

Schritt 5: Weiterleiten von Refs

Manchmal musst du von einer übergeordneten Komponente aus direkten Zugriff auf das tatsächliche <svg>-DOM-Element erhalten, vielleicht um seine Position zu messen oder es mit einer Drittanbieter-Bibliothek zu verwenden. Eine normale funktionale Komponente verbirgt ihre interne DOM-Struktur. Die Lösung ist React.forwardRef.

Ein ausgeklügelter Konverter wird die Komponente in React.forwardRef einhüllen, was einen Kanal schafft, um ein ref von der Elternkomponente direkt an das zugrundeliegende <svg>-Tag weiterzuleiten.

Die endgültige, produktionsreife Komponente sieht oft ungefähr so aus (TypeScript-Beispiel):

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'; // Gut für's Debugging
export default MyIcon;

Geschichten aus der Praxis

Der Theming-Albtraum

Ein Frontend-Team baute eine schicke Web-App mit Light- und Dark-Mode. Sie benutzten ungefähr 50 Icons, alle als <img src="/icons/whatever.svg"> implementiert. Die Icons waren schwarz. Als sie den Dark-Mode auslieferten, brach Panik aus: Alle 50 schwarzen Icons verschwanden auf dem neuen dunklen Hintergrund. Ihr erster panischer „Fix“ war, einen zweiten Satz weißer Icons (whatever-dark.svg) zu exportieren und überall üble bedingte Logik (isDarkMode ? 'whatever-dark.svg' : 'whatever.svg') zu schreiben. Es war ein Wartungsdesaster.

Dann führte ein Entwickler einen SVG-zu-JSX-Workflow ein. Sie ließen ein Skript laufen, das alle 50 SVGs in React-Komponenten umwandelte und dabei entscheidend alle fill="black"-Attribute durch fill="currentColor" ersetzte. Sie ersetzten alle <img>-Tags durch ihre neuen Icon-Komponenten, wie <WhateverIcon />. Sofort erbten die Icons ihre Farbe von der Textfarbe des Elternelements, was bereits vom CSS des Themes gehandhabt wurde. Light-Mode: schwarzer Text, schwarze Icons. Dark-Mode: weißer Text, weiße Icons. Es hat einfach funktioniert.

Lektion: Das Inlinen von SVGs als Komponenten ermöglicht eine nahtlose Integration in das bestehende Designsystem und Styling deiner App und bewahrt dich vor der Hölle des Asset-Managements.

Das animierte Häkchen

Ein Produktmanager wollte eine „entzückende“ Animation: Wenn ein Benutzer ein Formular ausfüllt, sollte sich ein Häkchen dynamisch auf dem Bildschirm zeichnen. Ein animiertes GIF kam nicht in Frage – es sah verpixelt aus und war eine riesige Datei. Die Entwicklerin versuchte, eine Bibliothek zu finden, aber nichts passte so recht zum individuellen Design des Häkchens.

Sie nahm die Sache selbst in die Hand, nahm das statische Häkchen-SVG vom Designer und konvertierte es in eine JSX-Komponente. Das gab ihr direkten Zugriff auf das <path>-Element des Häkchens in ihrem React-Code. Mit einer einfachen CSS-Transition auf die stroke-dasharray- und stroke-dashoffset-Eigenschaften dieses Pfades konnte sie genau den „Zeichnen“-Effekt erzeugen, den sie wollte. Die Animation war butterweich, unendlich skalierbar und benötigte weniger als 1 KB Code.

Lektion: Die Konvertierung eines SVGs in eine Komponente schaltet die granulare Kontrolle über seine einzelnen Teile frei und macht komplexe CSS- oder JavaScript-gesteuerte Animationen möglich.

Häufige Fehler und Fallen

  • Barrierefreiheit vergessen. Ein Icon, das eine Bedeutung vermittelt (wie ein „Schließen“-X), ist nicht nur Dekoration. Wenn du beim Konvertieren den <title>-Tag entfernst, könnte ein Screenreader es als „Gruppe“ ansagen oder einfach ignorieren. Stell immer sicher, dass deine finale Komponente ein passendes aria-label-Prop oder einen zugänglichen Namen über ein <title>-Element im SVG hat. Eine gute Komponente wird als <svg role="img" ...> gerendert.
  • Das Bundle aufblähen. Das Inlinen von SVGs bedeutet, dass ihr Code jetzt Teil deines JavaScript-Bundles ist. Bei ein paar Dutzend kleinen UI-Icons ist das ein Nettogewinn (weniger HTTP-Requests). Aber wenn du versuchst, eine riesige, komplexe Illustration mit Tausenden von Pfaden inline einzubinden, kannst du die Größe deines Bundles ernsthaft aufblähen und den initialen Ladevorgang verlangsamen. Für große, statische Illustrationen ist <img> immer noch eine absolut valide Wahl.
  • Die Optimierung ignorieren. SVGs, die aus Design-Tools wie Figma oder Adobe Illustrator exportiert werden, sind notorisch unordentlich. Sie enthalten Metadaten des Editors, Kommentare, versteckte Ebenen und übermäßig genaue Dezimalwerte. Das direkt in eine JSX-Komponente zu stopfen, führt zu aufgeblähtem, schwer lesbarem Code. Lass deine SVGs vor der Konvertierung immer durch einen Optimierer wie SVGO laufen. Das kann die Codegröße oft um 50 % oder mehr reduzieren.
  • Manuelle Bearbeitung wird zum Synchronisationsproblem. Du konvertierst icon.svg zu Icon.jsx. Dann passt du Icon.jsx manuell an, um ein Feature hinzuzufügen. Eine Woche später gibt dir der Designer eine aktualisierte icon.svg. Jetzt hast du die Wahl: die Konvertierung erneut ausführen und deine manuellen Änderungen verlieren, oder versuchen, das neue Design manuell in dein bearbeitetes JSX einzupflegen. Die „Source of Truth“ sollte die .svg-Datei sein; die Konvertierung zu JSX sollte ein wiederholbares, automatisiertes Skript sein.

Warum du das auf dem Schirm haben solltest

Du solltest darüber nachdenken, SVGs in JSX umzuwandeln, wann immer du eine komponentenbasierten Webanwendung (React, Preact usw.) baust und deine Icons mehr sein müssen als nur statische Bilder.

Es ist das richtige Werkzeug für den Job, wenn:

  • Du Icons brauchst, die ihre Farbe, Größe oder Strichstärke basierend auf State oder Props ändern.
  • Du ein Designsystem oder eine Komponentenbibliothek baust und einen skalierbaren, konsistenten Weg zur Verwaltung von Icons benötigst.
  • Du Teile eines Icons animieren möchtest.
  • Du auf Performance optimierst und die Anzahl der Netzwerk-Requests durch das Inlinen kritischer Icons reduzieren möchtest.

In der modernen Frontend-Entwicklung ist das Behandeln von Icons als Komponenten kein Hack – es ist der Standard für den Bau dynamischer, wartbarer und hochperformanter Benutzeroberflächen.

Tauche tiefer ein

Theorie erledigt. Zeit, loszulegen — 100 % in deinem Browser.

Tool ausprobieren: SVG zu JSX