In diesem Bereich gibt es einen Überblick über verschiedene Ansätze zur Gestaltung von React-Komponenten. Behandelt werden Inline-Styles, klassische CSS-Dateien, CSS-Module, Tailwind CSS sowie Lösungen wie styled-components. Am Ende kennst du die Vor- und Nachteile jeder Variante und kannst entscheiden, welche zu deinem Projekt passt.
Welche Styling-Variante wann?
| Ansatz | Stärke | Schwäche | Geeignet für |
|---|---|---|---|
| Inline-Styles | Sehr lokal, dynamische Werte einfach | Keine Pseudo-Selektoren, Keine Media Queries | Einzelne dynamische Anpassungen |
| Globales CSS / SCSS | Vertraut, gewohnte Toolchain | Namens-Kollisionen ohne Konvention | Bestehende Codebases, kleine Projekte |
| CSS Modules | Lokaler Scope, vertraute Syntax | Etwas Boilerplate | Mittlere bis große Projekte |
| Tailwind CSS | Sehr schnelles Prototyping, klein bundle | Gewöhnungsbedürftig in JSX | Apps mit eigenem Design |
| styled-components | CSS-in-JS, props-getrieben | Runtime-Overhead | Component-Bibliotheken, Themes |
| UI-Frameworks (Mantine, Chakra) | Fertige Komponenten | Wenig Spielraum bei Design | Schnelle interne Tools |
Im Folgenden alle Varianten mit Code-Beispielen.
Inline Styles
Der einfachste Ansatz React Components zu stylen ist die Verwendung von Inline Styles. Bei Inline Styles wird die Objekt-Notation verwendet.
const CardStyledInline = ({ cardTitle, children }) => {
return (
<div
className="styled_card"
style={{
border: '2px solid lightblue',
padding: '10px',
boxSizing: 'border-box',
borderRadius: '4px'
}}
>
<h2 style={{ marginTop: 0 }}>{cardTitle}</h2>
<div className="card_content">{children}</div>
</div>
);
};
export default CardStyledInline;Die Verwendung dieses Components erfolgt auf dem klassischen Wege.
<CardStyledInline cardTitle="Inline Styles">
<p>Ein Card-Element mit Inline-Styles.</p>
</CardStyledInline>
Inline Styles als Objekt
Da es sich bei den Inline-Styles um eine Objekt-Notation handelt, kann man diese genauso in einer Variable speichern oder von anderswo importieren.
Im folgenden Beispiel verlagern wir die Inline-Styles im CardStyledInline Component in eine Variable.
const CardStyledInline = ({ cardTitle, children }) => {
const cardStyles = {
border: '2px solid lightblue',
padding: '10px',
boxSizing: 'border-box',
borderRadius: '4px'
};
return (
<div
className="styled_card"
style={cardStyles}
>
<h2 style={{ marginTop: 0 }}>{cardTitle}</h2>
<div className="card_content">{children}</div>
</div>
);
};
export default CardStyledInline;CSS-Modules
CSS-Module sind eine der beliebtesten Lösungen für CSS-Kapselung in React.
CSS-Module transformieren Klassennamen zur Laufzeit, um sicherzustellen, dass sie einzigartig sind. Eine Klasse .button in einem Modul könnte zu etwas wie .MyComponent_button_1a2b3c kompiliert werden.
Hier ein Beispiel, um es besser zu greifen und zu verstehen.
Zuerst erstellen wir ein Button-Element direkt in unserer App.jsx. Dieses Button-Element stylen wir auf eine bestimmte Art und Weise.
import './App.scss';
const App = () => {
return (
<>
<button>Globaler Button</button>
</>
);
};In zugehöriger App.scss definieren wir Stile für diesen Button.
button {
padding: 6px;
color: #ffffff;
box-sizing: border-box;
border: 2px solid rgb(0, 73, 73);
}Unser globaler Button aus der App.jxs sieht also wie folgt aus.

Nun erstellen wir ein normales Component. Wir nennen ihn in diesem Fall CssModuleExample. Dort platzieren wir einen Button. Diesem Button geben wir zunächst gar keine Stile.
const CssModuleExample = () => {
return (
<button>
Component Button
</button>
);
};Wie wir sehen können, hat dieser Button die Stile aus der App.scss übernommen. Warum? Weil die Stile in React ohne gesonderter Kapselung global sind.

Nun werden wir CSS-Modul verwenden, um dieses Component zu mit den Stilen zu kapseln.
Dazu erstellen zu unserem Component die Daten CssModuleExample.module.css.
.button {
color: #ffffff;
border-radius: 6px;
border: 4px solid rgb(247, 104, 247);
background-color: rgb(152, 38, 152);
cursor: pointer;
font-size: 1.2rem;
}Diese CSS-Datei soll nun im Component selbst importiert werden.
import styles from './CssModuleExample.module.css';
const CssModuleExample = () => {
return (
<button className={styles.button}>Component Button</button>
);
};
export default CssModuleExample;Das Ergebnis zeigt nun, dass dieser Button tatsächlich abweichende Stile angenommen hat. Und zwar die, welche wir in der CssModuleExample.module.css definiert haben.

Der Builder (Vite oder Webpack) transformieren die Stile aus der verlinkten CSS und wandeln diese in JavaScript-Objekte um, welche wir dann über den vergebenen Namen, hier styles, ansprechen können.

Wenn wir also unsere Stile in der CssModuleExample.module.css ergänzen, wächst auch unsere JavaScript-Objekt mit den erzeugten Klassennamen als Schlüsselnamen im Objekt.
Angenommen, wir fügen folgende CSS-Definition hinzu.
.btn_primary {
color: #ffffff;
background-color: #b3680c;
}
Unser JavaScript-Objekt wird dann folgendermaßen aussehen.

Styled Components
Styled Components ist eine beliebte Bibliothek, um CSS direkt in JavaScript zu definieren und so Komponenten-basiertes Styling umzusetzen. Diese Bibliothek basiert auf Tagged Template Literals und nutzt die volle Power von JavaScript, um Styles dynamisch, wiederverwendbar und wartbar zu gestalten.
Installation
Bevor man diese Bibliothek verwenden kann, muss sie installiert werden. Das kann man mit folgender Anweisung im Root-Ordner des Projekts tun.
npm install styled-components
Damit ist die Bibliothek installiert und kann nun verwendet werden.
Beispiel - Ohne Stile
Wie immer, brauchen wir ein Beispiel, an dem alles verständlicher wird. Zuerst definieren wir ein normales Component, ohne besondere Stile.
const StyledComponentExample = () => {
return (
<>
<p>First paragraph.</p>
<p>Second paragraph.</p>
</>
);
};
export default StyledComponentExample;Als Ergebnis hätten wir reguläre Ausgabe von zwei p-Tags. Soweit nichts besonderes.

Beispiel - mit Stile
Nun importieren wir die Bibliothek, bzw. die Funktion styled aus styled-components.
Mit Hilfe von dieser Funktion können wir benutzerdefinierte Tags, eine Art Components, aufbauen und diesen spezifische Styles zuweisen.
In unserem Beispiel möchten wir ein Paragraph mit spezifischen Styles haben. Wir erstellen ein ParagraphLightBlue Component und weisen diesem bestimmte Stile zu.
import styled from 'styled-components';
const ParagraphLightBlue = styled.p`
padding: 10px;
border: 1px solid blue;
background-color: lightblue;
`;
const StyledComponentExample = () => {
console.log(styled);
return (
<>
<ParagraphLightBlue>First line.</ParagraphLightBlue>
<p>Second line.</p>
</>
);
};
export default StyledComponentExample;Statt unserem normalen p Tag, verwenden wir nun ParagraphLightBlue. Weil wir styled.p verwendet haben, erhalten wir ein p-Tag. Mit styled.div würden wir ein div-Elemente stattdessen erhalten.
Als Ergebnis erhalten wir unseren Paragraphen mit entsprechenden Styles, die wir über styled.p definiert haben.

Weil es sich hierbei um eine Art Component handelt, können wir es problemlos wiederverwenden. Wir ergänzen unser Beispiel und werden auch den zweiten Paragraphen durch ParagraphLightBlue ersetzen.
import styled from 'styled-components';
const ParagraphLightBlue = styled.p`
padding: 10px;
border: 1px solid blue;
background-color: lightblue;
`;
const StyledComponentExample = () => {
console.log(styled);
return (
<>
<ParagraphLightBlue>First line.</ParagraphLightBlue>
<ParagraphLightBlue>Second line.</ParagraphLightBlue>
</>
);
};
export default StyledComponentExample;
Props-basiertes Styling
Styled Components erlauben, Styles anhand von React-Props zu ändern.
Für diesen Fall erstellen wir ein React Component mit styled Verwendung StyledComponentButton. Dort definieren wird ein paar Stile für die Buttons.
import styled from 'styled-components';
const Button = styled.button`
color: #333333;
padding: 0.5em 1em;
border: none;
border-radius: 0;
display: inline-block;
background-color: #a3d6d6;
`;
const StyledComponentButton = () => {
return (
<>
<Button>Standard Button</Button>
<hr/>
<Button>Primary Button</Button>
</>
);
};
export default StyledComponentButton;Als Ergebnis haben wir folgende Ausgabe. Zwei gleich aussehende Buttons.

Anschließend erweitern wir unser Component und fügen die Verwendung von Props hinzu, sodass wir mithilfe von Props-Eigenschaften die Stile etwas anpassen können.
import styled from 'styled-components';
const Button = styled.button`
color: #333333;
padding: 0.5em 1em;
border: none;
border-radius: 0;
display: inline-block;
background-color: ${({ $primary }) =>
$primary ? '#68a7eb' : '#a3d6d6'};
`;
const StyledComponentButton = () => {
return (
<>
<Button>Standard Button</Button>
<hr/>
<Button $primary>Primary Button</Button>
</>
);
};
export default StyledComponentButton;Wie wir an der Ausgabe sehen können, sind die Buttons nun unterschiedlich. Dazu ist ebenfalls sichtbar, dass die eine CSS-Klasse gemeinem von beiden Buttons und eine unterschiedliche (für abweichende Stile) verwendet werden.

Tailwind CSS
Tailwind CSS ist ein Utility-First-Framework: Statt Klassen mit semantischer Bedeutung (.card-header) gibt es viele kleine Klassen, die jeweils eine CSS-Eigenschaft setzen (p-4, text-lg, bg-blue-500). Das Styling wandert direkt in die JSX-Klassen-Liste.
Installation
Im Vite-Projekt installiert man Tailwind als Dev-Dependency:
npm install -D tailwindcss @tailwindcss/viteIn vite.config.ts wird das Plugin registriert, in der zentralen CSS-Datei mit @import "tailwindcss"; eingebunden. Details und aktuelle Schritte: tailwindcss.com/docs/installation.
Beispiel
function Card({ title, children }) {
return (
<div className="rounded-lg border border-slate-200 p-4 shadow-sm">
<h2 className="mb-2 text-lg font-semibold text-slate-900">
{title}
</h2>
<div className="text-slate-700">{children}</div>
</div>
);
}Vor- und Nachteile
Vorteile:
- Kein Wechsel zwischen JSX und CSS-Datei – alles am gleichen Ort.
- Konsistentes Design-System per Konfiguration (Spacing, Farben, Breakpoints).
- Bundle bleibt klein, weil ungenutzte Klassen herausgepurged werden.
- Sehr schnelles Prototyping.
Nachteile:
- Lange Klassen-Listen können JSX überladen wirken lassen.
- Lernkurve: Tailwinds Klassennamen muss man kennen.
- Bei sehr individuellem Design braucht es Custom-Konfiguration.
Komponenten als „Klassen-Hülle"
Bei wiederkehrenden Stilen lohnt es sich, eine eigene Komponente zu definieren statt die Klassen-Listen überall zu duplizieren. Tailwind ersetzt nicht das Komponieren in React – es ergänzt es.
Bedingte Klassen mit clsx
Sobald Klassennamen bedingt zugewiesen werden sollen, wird die String-Konkatenation schnell unübersichtlich:
const className =
'btn ' +
(variant === 'primary' ? 'btn-primary ' : '') +
(disabled ? 'btn-disabled ' : '') +
(large ? 'btn-large' : '');Die Mini-Bibliothek clsx (oder classnames) löst das elegant:
npm install clsximport clsx from 'clsx';
function Button({ variant, disabled, large, children }) {
return (
<button
disabled={disabled}
className={clsx(
'btn',
variant === 'primary' && 'btn-primary',
disabled && 'btn-disabled',
large && 'btn-large'
)}
>
{children}
</button>
);
}clsx filtert false, null, undefined automatisch aus. Funktioniert mit klassischem CSS, CSS Modules und Tailwind gleichermaßen. In Tailwind-Projekten wird oft zusätzlich tailwind-merge (twMerge) eingesetzt, um konflikt-freie Klassenmerging zu erlauben.
Icons
Für React gibt es viele verschiedene Icon-Bibliotheken. In folgenden wird die Verwendung von React Icons gezeigt.
Zuerst soll das Paket im Projekt-Ordner installiert werden.
npm install react-icons --save
Im nächsten Schritt soll ein Icon ausgesucht werden, welches verwendet werden soll. Jedes Icon dieser Bibliothek ist ein Component. Dieses Component kann importiert und wie jedes andere Component verwendet werden.
import { CiDesktop } from "react-icons/ci";
const IconExample = () => {
return (
<span>
<CiDesktop />
</span>
);
};
export default IconExample;Man kann nun, wie in diesem Beispiel, das Icon in einem Component kapseln oder einfach in anderen Components einsetzen.
<IconExample />![]()
Konfiguration von Icons
React Icon stellen ein paar Konfigurationsoptionen bereit, welche man als Props in das jeweilige Icon-Component übergeben kann.
Im nächsten Beispiel erweitern wir die Verwendung von CiDesktop Icon um Angabe von size und color Eigenschaften.
import { CiDesktop } from "react-icons/ci";
const IconExample = () => {
return (
<span>
<CiDesktop size={100} color="teal" />
</span>
);
};
export default IconExample;![]()
Interessantes
Inline-Styles nutzen camelCase und Strings für Werte.
style={{ backgroundColor: 'red', fontSize: '14px' }} — Property-Namen in camelCase, Werte als Strings (mit Einheit) oder Zahlen (px implizit für viele Properties). KEIN background-color.
CSS Modules erzeugen scoped Klassen-Namen automatisch.
Eine Datei Button.module.css + import styles from './Button.module.css' + className={styles.btn} liefert eindeutige Klassen-Namen wie Button_btn__a1b2c. Keine Kollisionen mit anderen Komponenten.
clsx für conditionale Klassen — kürzer als Template-Strings.
className={clsx('btn', isActive && 'btn--active', size === 'lg' && 'btn--lg')} ist lesbarer als manuelle Template-Strings. clsx filtert falsy Werte automatisch.
className statt class — JSX-Regel.
class ist ein reserviertes Wort in JavaScript. In JSX heißt das Property className. Genauso wird for (Label) zu htmlFor. Der Linter eslint-plugin-react fängt das ab.
Inline-Styles erzeugen pro Render ein neues Object.
style={{ color: 'red' }} erzeugt jedes Mal ein neues Object — bei React.memo-Kindern führt das zu unnötigen Re-Renders. Lösung: das Object außerhalb der Komponente extrahieren oder mit useMemo stabilisieren.
SCSS in Vite/Webpack — meist nur ein Plugin installieren.
Bei Vite: npm install -D sass-embedded, dann ist import './x.scss' sofort nutzbar. Bei Webpack: sass-loader. Keine zusätzliche Konfiguration nötig in modernen Setups.
styled-components vs. CSS Modules — Build-Time vs. Runtime.
CSS Modules werden beim Build verarbeitet (kein Runtime-Overhead). styled-components generieren CSS zur Laufzeit (kleiner Runtime-Cost, aber mächtiger). Bei Performance-kritischen Anwendungen: CSS Modules oder neuere Build-Time-CSS-in-JS-Lösungen.
React Icons importiert pro Icon einzeln — Tree-Shaking nutzen.
import { CiDesktop } from 'react-icons/ci' importiert nur dieses Icon. Bundler shaken den Rest weg. NICHT import * as Icons from 'react-icons' — das zieht alle 30.000 Icons rein.
Weiterführende Ressourcen
Externe Quellen
- Styling React Components – react.dev
- CSS Modules – GitHub
- styled-components – Documentation
- clsx – GitHub
- React Icons – Library