Wie baut man eine Komponentenbibliothek auf?
Eine Komponentenbibliothek (component library) ist gemeinsamer Code, in dem Teile der Oberfläche wie Button oder Formularfeld einmal geschrieben werden. Jeder Screen ruft diese Teile von dort auf. Jede Komponente hat einen Namen, Einstellungen (Props), Zustände und eine Dokumentation. Ich beginne mit einem Inventar des Produkts und schreibe dann die API des meistgenutzten Teils.
Kurz gesagt
Eine Komponentenbibliothek ist Code, in dem die sich wiederholenden Teile der Oberfläche an einer Stelle liegen. Braucht ein Screen einen Button, schreibt die Entwicklung ihn nicht neu, sondern ruft ihn aus der Bibliothek auf. Das Design nutzt in Figma das Teil mit demselben Namen.
Die Bibliothek ist ein Teil eines Designsystems, nicht das Ganze. Die Regeln des Systems und das Team, das es steuert, beschreibe ich in jenem Ratgeber. Diese Seite erklärt nur, wie die Bibliothek aufgebaut wird.
- Eine Komponente erfüllt eine Aufgabe und kennt keine Rohfarbe. Farben und Maße liest sie aus benannten Werten, den Design Tokens.
- Das eigentliche Produkt der Bibliothek ist die API der Komponenten: welche Einstellungen sie annimmt und was als Standard gilt.
- Ein UI-Kit entsteht in derselben Reihenfolge. Der Unterschied: Ein UI-Kit bleibt oft nur in der Designdatei.
Zuerst das Inventar: Was kommt in die Bibliothek?
Eine Bibliothek beginnt nicht mit einer leeren Seite. In Ihrem Produkt gibt es schon Dutzende Buttons, Formularfelder und Karten. Der erste Schritt ist, sie zu sammeln.
Ich mache von jedem Screen einen Screenshot und klebe die Teile nach Art sortiert auf dieselbe Tafel. Die Methode, die Brad Frost Interface-Inventar nennt, beschreibe ich Schritt für Schritt im Ratgeber zum Designsystem. Hier erzähle ich, wie ich aus dem Inventar eine Reihenfolge ableite.
Ist das Inventar fertig, schreibe ich neben jede Art zwei Zahlen: auf wie vielen Screens sie vorkommt und wie viele verschiedene Varianten sie hat. Das Teil, das am häufigsten vorkommt und am uneinheitlichsten ist, steht oben auf der Liste. In den Produkten, die ich prüfe, ist es meistens der Button.
Atomic Design: Teile benennen
Beim Gruppieren der Teile aus dem Inventar schaue ich auf Brad Frosts Modell. In seinem Buch Atomic Design von 2016 beschreibt Frost die Oberfläche in fünf Stufen. Die Definitionen in der Tabelle sind kurze Übersetzungen aus seinem Text.
| Stufe | Laut Frost | Beispiel |
|---|---|---|
| Atom | Grundbaustein, der sich nicht weiter teilen lässt, ohne seine Funktion zu verlieren. | Button, Label, Eingabefeld |
| Molekül | Einfache Gruppe von Teilen, die zusammen wie eine Einheit funktionieren. | Suchformular aus Label, Feld und Button |
| Organismus | Relativ komplexe Komponente aus Gruppen von Molekülen, Atomen oder anderen Organismen. | Website-Kopf, Produktraster |
| Template | Struktur auf Seitenebene, die Komponenten in ein Layout setzt. | Template für die Produktdetailseite |
| Seite | Das Template, gefüllt mit echtem Inhalt. | Die Seite eines bestimmten Produkts |
Frost warnt zweimal. Erstens ist Atomic Design kein linearer Prozess, sondern ein Denkmodell. Zweitens verabschiedet er sich bei den Templates von der Chemie-Metapher. Er schreibt, dass eine zu weit getriebene Metapher Stakeholder verwirren kann.
Trotzdem lege ich im Code keine Ordner „atoms“ oder „molecules“ an. Ich benenne Komponenten nach ihrer Aufgabe: Button, SearchForm, ProductCard. Das Modell hilft, wenn man darüber spricht, was was enthält.
Die API einer Komponente: wie man Props gestaltet
Die API einer Komponente sind die Einstellungen, die man beim Aufruf übergeben kann. In React heißen sie Props. Die React-Dokumentation beschreibt Props als einziges Argument einer Komponente. Die übergeordnete Komponente gibt Informationen per Props an die untergeordnete weiter.
Dieselbe Dokumentation betont zwei Regeln. Props sind schreibgeschützt, eine Komponente ändert ihre eigenen Props nicht. Braucht es Interaktion, nutzt man State. Auch der Standardwert wird beim Schreiben der Props vergeben, etwa size = 100.
Beim Aufbau einer React-Komponentenbibliothek halte ich mich an diese Regeln:
- Benennen Sie ein Prop nach seiner Bedeutung. Schreiben Sie
variant="primary"stattcolor="black". Ändert sich die Markenfarbe, bleibt die API gleich. - Halten Sie die Optionen begrenzt.
sizenimmt nursm,mdundlgan. Freie Werte bringen die Unordnung aus dem Inventar zurück. - Der Standard ist der häufigste Zustand. Eine Komponente, die ohne Einstellung aufgerufen wird, sollte auf den meisten Screens richtig aussehen.
- Nutzen Sie boolesche Props für An und Aus.
disabledoderloadingsind standardmäßig aus. - Nehmen Sie das Label als Text an. Die Beschriftung des Buttons kommt vom Aufrufer. So lässt sich der Text eines CTA-Buttons auf jedem Screen passend zur Aktion schreiben.
Halten Sie die Hintertür schmal
Jede Bibliothek trifft irgendwann auf einen Bedarf, den sie nicht vorhergesehen hat. Deshalb sollte eine Komponente die Attribute des HTML-Elements unverändert durchreichen können. Werte wie type, aria-label oder form gehen direkt an das darunterliegende <button>.
Beim Stil halte ich die Tür dagegen schmal. Jeder Komponente eine freie style- oder Klasseneinstellung zu geben, ist nur eine höflichere Form des Kopierens. Gibt ein Team denselben Stil zum zweiten Mal von außen mit, verdient dieser Stil eine neue Variante in der Bibliothek.
Gleichen Sie die Namen mit der Designdatei ab. Heißt die Einstellung der Komponente in Figma „Size: Large“, sollte es im Code size="lg" sein. Nutzen Design und Entwicklung dasselbe Wort, braucht es beim Handoff keine Übersetzung.
Am leichtesten testen Sie eine API, indem Sie die eine Zeile schreiben, die sie aufruft. Bleibt die Zeile kurz und lesbar, ist die API gut. Unten können Sie die Einstellungen eines Buttons ändern und sehen, wie sich diese Zeile ändert.
Ausprobieren: die Button-API
Wählen Sie die Einstellungen. Vorschau und beide Codezeilen ändern sich zusammen. Mit den Pfeiltasten bewegen Sie sich innerhalb einer Gruppe.
variant
size
Zustand und Icon
Python (wie auf dieser Website)
button("Speichern", variant="primary")
React
<Button variant="primary">Speichern</Button>
Vorschau: primary, normale Größe, aktiver Button.
Der Button in der Vorschau nutzt den echten .btn-Stil dieser Website. Die Python-Zeile hat die Form der Funktion ui.button() der Website. Diese Funktion nimmt variant, size und arrow. disabled habe ich als Beispiel ergänzt. Die React-Zeile ist die JSX-Entsprechung derselben API.
Schalten Sie disabled ein, wird der Vorschau-Button blass und nimmt keinen Klick an. Der Stil dafür steht einmal in der CSS-Datei der Komponente. Kein Screen schreibt diese Regel selbst.
Variante oder eigene Komponente?
Je größer die Bibliothek, desto öfter höre ich diese Frage. Ist eine neue Button-Art dazugekommen oder eine neue Komponente? Mein Maßstab ist das Verhalten.
Macht das Teil dasselbe und ändert sich nur das Aussehen, ist es eine Variante. Primärer und sekundärer Button tun dasselbe: Beim Drücken starten sie eine Aktion. Deshalb sind beide die Einstellung variant einer einzigen Komponente.
Ändern sich Verhalten, Inhalt oder Rolle für die Barrierefreiheit, ist es eine eigene Komponente. Ein Link zu einer anderen Seite bleibt ein Link, auch wenn er wie ein Button aussieht. Auch ein Button, der ein Menü öffnet und schließt, bringt eigene Tastaturregeln mit.
| Fall | Meine Entscheidung |
|---|---|
| Derselbe Button, andere Farbe oder Größe | Variante (variant, size) |
| Icon neben dem Button | Einstellung (icon) |
| Button, der gedrückt bleibt, zum Umschalten | Einstellung, aber der Zustand wird mit aria-pressed gemeldet |
| Teil, das wie ein Button aussieht und zu einer anderen Seite führt | Eigene Komponente oder Link-Element |
| Button, der ein Ausklappmenü öffnet | Eigene Komponente |
Es gibt auch ein Warnzeichen: Schreiben Sie für ein neues Prop den dritten if-Block in die Komponente, quetschen Sie sehr wahrscheinlich zwei Komponenten in eine Datei.
Schreiben Sie Zustände von Anfang an
Was Sie im Inventar nicht sehen, sind Zustände. Ein Screenshot zeigt den Button nur im Ruhezustand. Der Nutzer sieht ihn aber auch in anderen Momenten: mit dem Mauszeiger darüber, mit Tastaturfokus, beim Drücken und beim Warten auf einen Vorgang.
Ich halte den Code einer Komponente erst für fertig, wenn diese Zustände geschrieben sind: Standard, Hover, Fokus, gedrückt, deaktiviert und Laden. Bei Formularfeldern kommt ein Fehlerzustand hinzu. Wie man Fehlertexte schreibt, habe ich im Muster Fehlermeldungen gesammelt.
Auch Regeln zur Barrierefreiheit hängen an Zuständen. Laut dem Button-Muster des W3C löst die Leertaste oder Enter einen fokussierten Button aus. Ist die Aktion nicht verfügbar, bekommt er aria-disabled="true".
Dasselbe Muster gibt eine klare Regel für Buttons, die gedrückt bleiben. Der Zustand wird mit aria-pressed gemeldet, und das Label ändert sich nicht, wenn sich der Zustand ändert. Soll sich das Label ändern, etwa von „Ton aus“ zu „Ton an“, nutzt man aria-pressed nicht.
Auch die Größe des Tippziels ist Sache der Komponente. Selbst die kleine Variante muss sich mit dem Finger bequem drücken lassen. Die Maße finden Sie im Muster Tippbereich, alle Kriterien im WCAG-Ratgeber.
Dokumentation und Storybook
Eine Komponente ohne Dokumentation wird kopiert und verändert. Auf die Seite jeder Komponente schreibe ich: wofür sie da ist, wann man sie nicht nutzt, welche Einstellungen sie annimmt und ihre Standards, ihre Zustände und ein kopierbares Codebeispiel.
Diese Seiten von Hand aktuell zu halten, ist schwer. Dafür können Sie das Werkzeug Storybook nutzen. Storybook beschreibt sich als Frontend-Werkstatt, um UI-Komponenten und Seiten getrennt von der Anwendung zu entwickeln.
In Storybook heißt jeder Zustand „Story“. Laut Dokumentation hält eine Story einen gerenderten Zustand einer Komponente fest. Die Einstellungen der Komponente stehen in einem einzigen JavaScript-Objekt namens „args“. Ändert sich ein Arg, wird die Komponente neu gerendert.
Für den Button oben könnten zwei Stories so aussehen:
export default { component: Button, args: { children: 'Speichern' } };
export const Primaer = { args: { variant: 'primary' } };
export const Deaktiviert = { args: { variant: 'primary', disabled: true } };
Die Args in der ersten Zeile liegen auf Komponentenebene und gelten für jede Story. Args in einer Story gelten nur für diese Story. Die Storybook-Dokumentation beschreibt beide Ebenen getrennt.
Storybook arbeitet offiziell mit React, Vue, Angular, Svelte und Web Components. Laut Dokumentation kann es Komponenten analysieren und neben den Stories automatisch Dokumentation erzeugen. Stories sind außerdem eine fertige Grundlage für UI-Tests.
Versionierung: wie Sie Änderungen ankündigen
Nutzen mehrere Projekte die Bibliothek, trifft jede Änderung jemanden. Die Versionsnummer ist eine kurze Nachricht, die sagt, wie riskant die Änderung ist. Ich nutze die Regeln von Semantic Versioning 2.0.0.
- MAJOR: Eine nicht abwärtskompatible Änderung. Beispiel: das Prop
colorentfernen und durchvariantersetzen. - MINOR: Eine abwärtskompatible neue Funktion. Beispiel:
size="lg"für den Button hinzufügen. - PATCH: Eine abwärtskompatible Fehlerbehebung. Beispiel: einen Fehler beheben, bei dem der Fokusring verschwand.
Laut Semver sind Versionen 0.y.z für die erste Entwicklung, alles kann sich jederzeit ändern. 1.0.0 ist die erste Version, die die öffentliche API festlegt. Laut den FAQ des Dokuments sollte Software, die in Produktion läuft, wahrscheinlich schon 1.0.0 sein.
Markieren Sie ein Prop als veraltet (deprecated), bevor Sie es entfernen. Semver verlangt diese Markierung in einer MINOR-Version. Die FAQ empfehlen außerdem, vor dem Entfernen mindestens eine MINOR-Version mit dieser Warnung zu veröffentlichen. So haben Nutzer Zeit für den Umstieg.
Das Beispiel dieser Website
Die Oberfläche von ux.center läuft mit einer kleinen Komponentenbibliothek. Den Aufbau beschreibt die Datei DESIGN.md der Website. Die Schichten sind: Tokens, Komponenten, Sektionen und Seite. Jede Schicht stützt sich nur auf die darunter.
Die Regel ist einfach: Eine Komponente ist eine CSS-Datei und meist eine Python-Funktion. Für den Button gibt es src/ds/components/button.css und die Funktion button() in ui.py. Die Funktion nimmt Label, Link und die Einstellungen variant, size und arrow an.
Varianten kommen im CSS über Modifier-Klassen dazu: btn--primary, btn--accent, btn--sm, btn--lg. Die Grundregel .btn bleibt unberührt. Die Komponenten lesen keine Rohfarben, sondern semantische Tokens wie --surface oder --accent.
Ehrlich gesagt: button() erzeugt einen Link und nimmt deshalb kein disabled an. Die deaktivierte Darstellung ist im CSS definiert und funktioniert bei echten <button>-Elementen wie in der Demo oben. Das ist eine Lücke, die in der Bibliothek noch offen ist.
Das Build-Skript fasst alle Komponentendateien in einer einzigen CSS-Datei zusammen. Braucht es ein neues Teil, kommt zuerst eine Datei in den Komponentenordner, dann eine Zeile in die Tabelle des Designdokuments.
Meine Notiz
Das häufigste Problem in Audits ist die kopierte Komponente. Das Team hat statt des Buttons aus der Bibliothek einen ähnlichen geschrieben, weil die nötige Einstellung fehlte. Nach einer Weile kursieren mehrere Fassungen desselben Buttons im Produkt.
Dagegen hilft, einen Wunsch an die Bibliothek leichter zu machen als das Kopieren. Auf jede Komponentenseite schreibe ich eine Zeile „Wenn diese Komponente nicht passt“ und einen Kontaktweg.
In einem kleinen Team empfehle ich, mit zehn Komponenten zu beginnen. Bauen Sie zuerst die meistgenutzten Teile wie Button und Formularfeld gut. Den Rest fügen Sie hinzu, wenn er gebraucht wird. Was beim Weg von Figma in den Code verloren geht, beschreibe ich im Ratgeber Design Handoff.
Wollen Sie Ihre Bibliothek mit mir zusammen aufbauen, ist der Design & Ship Sprint genau dafür da. In zwei Wochen liefere ich Design und Code in Ihr Repository.
Häufige Fragen
Sind Komponentenbibliothek und Designsystem dasselbe?
Nein. Die Komponentenbibliothek sind die im Code wiederverwendeten Teile der Oberfläche. Das Designsystem umfasst sie zusammen mit Stilregeln, Mustern und dem Team, das das System steuert.
Was ist der Unterschied zwischen UI-Kit und Komponentenbibliothek?
Ein UI-Kit sind meist fertige Teile in der Designdatei. Die Komponentenbibliothek ist die im Code geschriebene Fassung dieser Teile, mit Einstellungen und Zuständen. Beide sollten dieselben Namen tragen.
Braucht eine Komponentenbibliothek Storybook?
Nein. Storybook macht es leichter, Komponenten getrennt von der Anwendung zu zeigen und zu dokumentieren. In einer kleinen Bibliothek reicht auch eine Seite pro Komponente, die ihre Zustände zeigt.
Wie ändert sich die Versionsnummer, wenn ich ein Prop entferne?
Laut Semantic Versioning erhöht jede nicht abwärtskompatible Änderung die MAJOR-Version. Markieren Sie das Prop zuerst in einer MINOR-Version als veraltet und entfernen Sie es dann in einer MAJOR-Version.
Quellen (6)
- Brad Frost, Atomic Design, Kapitel 2: Atomic Design Methodology. 2016
- Storybook, Storybook Docs: Introduction. abgerufen am 3.11.2026
- Storybook, Args. abgerufen am 3.11.2026
- Tom Preston-Werner, Semantic Versioning 2.0.0 (semver.org). abgerufen am 3.11.2026
- W3C WAI, ARIA Authoring Practices Guide: Button Pattern. abgerufen am 3.11.2026
- React, Passing Props to a Component. abgerufen am 3.11.2026