Von Design-Tokens bis zur automatisierten Dokumentation
Eine Sammlung wiederverwendbarer Vue-Komponenten ist noch kein Design System. Erst Design-Tokens als einzige Wahrheitsquelle für Farben und Abstände, eine bewusst entworfene Komponenten-API und verbindliche Versionierung machen aus losen Bausteinen ein System, das Teams über Projektgrenzen hinweg konsistent nutzen können.
Inhaltsverzeichnis
- 1. Was ein Design System von einer Komponentensammlung unterscheidet
- 2. Design-Tokens als einzige Wahrheitsquelle
- 3. Komponenten-API bewusst entwerfen
- 4. Theming und Dark Mode über CSS-Variablen
- 5. Paketstruktur und Build-Setup
- 6. Versionierung und Breaking-Change-Kommunikation
- 7. Dokumentation mit Storybook automatisieren
- 8. Governance: Beiträge und Akzeptanzkriterien
- 9. Design-System-Ansätze im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Was ein Design System von einer Komponentensammlung unterscheidet
Viele Teams glauben, ein Design System mit Vue-Komponenten zu besitzen, sobald sie einen Ordner mit wiederverwendbaren Buttons, Inputs und Karten haben. Tatsächlich ist das nur die sichtbare Oberfläche. Ein echtes Design System besteht aus drei Schichten: den Design-Tokens als abstrakte Designentscheidungen, den Vue-Komponenten als deren technische Umsetzung, und der Dokumentation, die beides für Design und Entwicklung nachvollziehbar macht. Fehlt eine dieser Schichten, entsteht schnell wieder Inkonsistenz zwischen Produkten.
Der eigentliche Wert eines Design Systems mit Vue-Komponenten zeigt sich, sobald mehr als ein Projekt oder Team es verwendet. Eine einzelne Anwendung braucht kein separates Paket, interne Komponenten im selben Repository reichen aus. Sobald aber mehrere Vue-Anwendungen, etwa ein Shop-Frontend und ein internes Admin-Tool, dieselbe visuelle Sprache sprechen sollen, lohnt sich die Investition in ein eigenständig versioniertes, dokumentiertes Paket erheblich.
Ein häufiger Fehler beim Aufbau eines Design Systems mit Vue ist, mit den Komponenten zu beginnen, statt mit den Tokens. Wer zuerst zehn Buttons mit hart kodierten Hex-Farben baut und danach versucht, ein Theming-System nachzurüsten, muss jede Komponente einzeln anpassen. Der umgekehrte Weg, zuerst Tokens definieren, dann Komponenten darauf aufbauen, spart diesen nachträglichen Umbau vollständig.
2. Design-Tokens als einzige Wahrheitsquelle
Design-Tokens sind benannte, plattformunabhängige Werte für Farben, Abstände, Schriftgrößen und Radien, typischerweise in JSON oder YAML definiert und über ein Tool wie Style Dictionary in verschiedene Ausgabeformate transformiert, etwa CSS-Custom-Properties für Vue-Komponenten und gleichzeitig Swift- oder Kotlin-Konstanten für native Apps. Der entscheidende Vorteil: Eine Designentscheidung wird an genau einer Stelle getroffen und propagiert automatisch in alle Plattformen.
Für ein Design System mit Vue-Komponenten werden die generierten CSS-Custom-Properties direkt in den Komponenten referenziert, nie hart kodierte Werte. Das erlaubt Theme-Wechsel zur Laufzeit, ohne eine einzige Komponente neu zu kompilieren, und macht Design-Anpassungen für Whitelabel-Projekte trivial: Ein neues Set von Token-Werten reicht aus, die Vue-Komponenten selbst bleiben unverändert.
// tokens/color.json — Source of truth for design tokens, transformed by Style Dictionary
{
"color": {
"brand": {
"primary": { "value": "#16a34a" },
"primary-dark": { "value": "#064e3b" }
},
"text": {
"default": { "value": "#1e293b" },
"muted": { "value": "#64748b" }
},
"surface": {
"default": { "value": "#ffffff" },
"elevated": { "value": "#f8fafc" }
}
},
"spacing": {
"sm": { "value": "8px" },
"md": { "value": "16px" },
"lg": { "value": "24px" }
}
}
// Generated output: dist/tokens.css (consumed by every Vue component)
// :root {
// --color-brand-primary: #16a34a;
// --color-text-default: #1e293b;
// --spacing-md: 16px;
// }
3. Komponenten-API bewusst entwerfen
Die Props- und Slots-Signatur einer Vue-Komponente im Design System ist ein langfristiger Vertrag, nicht ein internes Implementierungsdetail. Sobald ein Button aus dem Design System in Dutzenden Vue-Anwendungen verwendet wird, wird jede Änderung an seiner Props-Signatur zu einer Breaking-Change-Kommunikation über Teamgrenzen hinweg. Deshalb sollte die API jeder Komponente von Anfang an auf Stabilität ausgelegt sein: benannte, semantische Prop-Werte wie variant="primary" statt beliebiger CSS-Klassen von außen, und explizite Slots für Erweiterbarkeit statt zusätzlicher Props für jeden Sonderfall.
Ein bewährtes Muster für Vue-Design-System-Komponenten ist, gestaltende Eigenschaften über streng typisierte Props zu steuern, während beliebiger Inhalt über Slots eingebracht wird. Ein Button-Komponente definiert etwa variant, size und disabled als Props mit begrenztem Wertebereich, während der eigentliche Button-Text über den Default-Slot kommt. Das verhindert, dass Konsumenten beliebige Tailwind-Klassen von außen injizieren und damit die visuelle Konsistenz unterlaufen, die das Design System eigentlich garantieren soll.
// DesignSystemButton.vue — API designed for stability, not for flexibility at any cost
<script setup lang="ts">
type Variant = 'primary' | 'secondary' | 'danger' | 'ghost';
type Size = 'sm' | 'md' | 'lg';
interface Props {
variant?: Variant;
size?: Size;
disabled?: boolean;
loading?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
size: 'md',
disabled: false,
loading: false,
});
const emit = defineEmits<{ click: [event: MouseEvent] }>();
// Only design-system-owned class names — consumers cannot inject arbitrary utility classes
const variantClass = computed(() => `ds-btn--${props.variant}`);
const sizeClass = computed(() => `ds-btn--${props.size}`);
</script>
<template>
<button
:class="['ds-btn', variantClass, sizeClass, { 'ds-btn--loading': loading }]"
:disabled="disabled || loading"
@click="emit('click', $event)"
>
<slot name="icon-left" />
<slot />
<slot name="icon-right" />
</button>
</template>
4. Theming und Dark Mode über CSS-Variablen
Theming in einem Vue Design System sollte niemals über bedingte Props wie dark-mode="true" in jeder einzelnen Komponente gelöst werden. Der robustere Weg ist ein Wrapper-Attribut, etwa data-theme="dark" auf dem Root-Element der Anwendung, kombiniert mit CSS-Custom-Properties, die pro Theme unterschiedliche Werte annehmen. Jede Design-System-Komponente referenziert dieselben Variablennamen, unabhängig vom aktiven Theme, und muss selbst keine Kenntnis vom Theming-Mechanismus haben.
Für Whitelabel-Szenarien mit mehreren Marken funktioniert derselbe Mechanismus: Ein zusätzliches Attribut wie data-brand="acme" lädt einen anderen Satz von Token-Werten, ohne dass eine einzige Vue-Komponente angepasst werden muss. Diese Entkopplung zwischen visueller Erscheinung und Komponenten-Logik ist einer der wichtigsten Architekturentscheidungen beim Aufbau eines langlebigen Design Systems mit Vue.
/* tokens/theme.css — Same variable names, different values per theme attribute */
:root,
[data-theme="light"] {
--color-surface-default: #ffffff;
--color-text-default: #1e293b;
--color-brand-primary: #16a34a;
}
[data-theme="dark"] {
--color-surface-default: #0f172a;
--color-text-default: #e2e8f0;
--color-brand-primary: #4ade80;
}
/* Whitelabel: a second attribute swaps brand values independently of the theme */
[data-brand="acme"] {
--color-brand-primary: #db2777;
}
/* Every Vue component references only the variable name, never a raw hex value */
.ds-btn--primary {
background: var(--color-brand-primary);
color: var(--color-surface-default);
}
5. Paketstruktur und Build-Setup
Ein Design System mit Vue-Komponenten wird üblicherweise als eigenständiges npm-Paket mit Vite als Library-Build ausgeliefert. Wichtig ist, Vue selbst als peerDependency zu deklarieren, nicht als reguläre Abhängigkeit, damit konsumierende Anwendungen ihre eigene Vue-Version mitbringen, statt eine zweite Vue-Instanz aus dem Design-System-Paket zu laden. Der Build erzeugt typischerweise sowohl ein ESM- als auch ein CommonJS-Bundle, um sowohl moderne Vite-Projekte als auch ältere Webpack-Setups zu unterstützen.
Die interne Struktur des Pakets trennt Tokens, Komponenten und Composables in eigene Unterordner mit eigenen Export-Einstiegspunkten. Das ermöglicht Tree-Shaking: Eine Anwendung, die nur den Button und das Input-Feld nutzt, muss nicht das komplette Design-System-Bundle laden, sondern importiert gezielt einzelne Komponenten über Subpath-Exports.
// vite.config.js — Library build for the design system package
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import dts from 'vite-plugin-dts';
export default defineConfig({
plugins: [vue(), dts({ include: ['src'] })],
build: {
lib: {
entry: {
index: 'src/index.ts',
button: 'src/components/Button/index.ts',
input: 'src/components/Input/index.ts',
},
formats: ['es', 'cjs'],
},
rollupOptions: {
// Vue must never be bundled into the design system itself
external: ['vue'],
output: { globals: { vue: 'Vue' } },
},
},
});
// package.json — vue declared as peer dependency, never a direct one
// "peerDependencies": { "vue": "^3.4.0" }
6. Versionierung und Breaking-Change-Kommunikation
Semantic Versioning ist für ein Design System mit Vue-Komponenten nicht optional, weil Dutzende konsumierende Anwendungen sich auf stabile Major-Versionen verlassen müssen. Jede Änderung an Props, Slots oder dem visuellen Erscheinungsbild einer Komponente muss klassifiziert werden: Ein neues optionales Prop ist ein Minor-Release, eine geänderte Prop-Semantik oder ein entfernter Slot ist ein Major-Release. Changesets oder ein vergleichbares Tool automatisiert diese Klassifizierung und generiert daraus einen konsistenten Changelog.
Bei Major-Releases eines Vue-Design-Systems empfiehlt sich eine Übergangsphase mit Codemods, die konsumierende Anwendungen automatisiert auf die neue API migrieren, statt jedes Team manuell durch die Breaking Changes zu führen. Ohne diese Investition bleiben Teams häufig auf veralteten Major-Versionen hängen, weil die manuelle Migration zu aufwendig erscheint, was langfristig die Fragmentierung zurückbringt, die das Design System eigentlich verhindern sollte.
#!/usr/bin/env bash
# Publishing a new design system version with automated changelog generation
set -euo pipefail
# Changesets reads the pending change files and determines the version bump
npx changeset version
# Classify: patch = bugfix, minor = new optional prop, major = removed slot/prop
npm run build
npm run test
npm run test:visual -- --ci
npx changeset publish
echo "[OK] Published new design system version with generated changelog"
7. Dokumentation mit Storybook automatisieren
Ohne lebendige Dokumentation verliert ein Design System mit Vue-Komponenten schnell an Akzeptanz, weil Entwickler lieber eine eigene Komponente bauen, als die Props einer undokumentierten bestehenden Komponente im Quellcode nachzuschlagen. Storybook ist für Vue-Design-Systeme der De-facto-Standard, weil es jede Komponente isoliert rendert, alle Props über Controls interaktiv veränderbar macht und Variant-Kombinationen automatisch aus TypeScript-Typen ableiten kann.
Wichtig ist, Storybook nicht nur als Showcase, sondern als Testinstrument zu nutzen: Visuelle Regressionstests über Chromatic oder Playwright erkennen unbeabsichtigte optische Änderungen an Design-System-Komponenten, bevor sie in Produktion in Dutzenden Anwendungen sichtbar werden. Die Dokumentation sollte zudem Verwendungsrichtlinien enthalten, nicht nur technische Props, etwa wann variant="danger" angemessen ist und wann nicht.
8. Governance: Beiträge und Akzeptanzkriterien
Ein Design System mit Vue-Komponenten ohne klaren Beitragsprozess wird entweder zum Flaschenhals, weil ein einzelnes Team jede Änderung reviewen muss, oder zum Wildwuchs, weil jedes Team eigene Komponenten ins gemeinsame Paket schiebt. Ein funktionierendes Governance-Modell definiert explizite Akzeptanzkriterien: Eine neue Komponente braucht Design-Abnahme, Barrierefreiheitsprüfung, Storybook-Dokumentation und mindestens zwei unabhängige konsumierende Anwendungen, bevor sie ins Kernpaket aufgenommen wird.
Viele erfolgreiche Design-System-Teams etablieren zusätzlich einen Office-Hour-Rhythmus oder ein RFC-Verfahren für größere API-Änderungen, sodass konsumierende Teams frühzeitig Einfluss nehmen können, statt erst bei der Migration von einem Breaking Change überrascht zu werden. Diese organisatorische Disziplin ist am Ende oft wichtiger für den langfristigen Erfolg als jede einzelne technische Entscheidung bei den Vue-Komponenten selbst.
9. Design-System-Ansätze im Vergleich
Es gibt unterschiedliche Reifegrade, ein Design System mit Vue-Komponenten zu betreiben, von der einfachen Komponentensammlung im Monorepo bis zum vollständig eigenständigen, unabhängig versionierten Produkt mit eigenem Team.
| Ansatz | Konsistenz | Wartungsaufwand | Eignung |
|---|---|---|---|
| Copy-Paste-Komponenten | Gering | Niedrig pro Kopie | Einzelprojekt, Prototyp |
| Shared Folder im Monorepo | Mittel | Mittel | Wenige verwandte Projekte |
| Eigenständiges npm-Paket | Hoch | Erhöht, dediziertes Team sinnvoll | Mehrere unabhängige Produkte |
| Token-getriebenes System | Sehr hoch | Hoch, Tooling nötig | Multi-Plattform, Whitelabel |
Die meisten Vue-Organisationen wachsen organisch von der Copy-Paste-Phase über den Shared Folder bis zum eigenständigen npm-Paket. Ein Token-getriebenes System mit Style Dictionary lohnt sich erst, sobald Multi-Plattform-Konsistenz oder Whitelabeling explizit gefordert sind, weil das zusätzliche Tooling einen spürbaren Wartungsaufwand mit sich bringt.
Mironsoft
Design Systeme, Vue-Komponentenbibliotheken und Frontend-Konsistenz
Ein Design System, das Teams wirklich nutzen?
Wir bauen Design-Tokens, Vue-Komponenten-API und Storybook-Dokumentation als versioniertes Paket auf, das mehrere Anwendungen konsistent versorgt und langfristig wartbar bleibt.
Tokens & Theming
Design-Tokens mit Style Dictionary und Dark-Mode-fähigem Theming aufbauen
Komponenten-API
Stabile, typisierte Vue-Komponenten mit langfristig tragbarem Vertrag
Doku & Governance
Storybook-Setup und Beitragsprozess für nachhaltige Akzeptanz
10. Zusammenfassung
Ein Design System mit Vue-Komponenten ist mehr als eine Sammlung wiederverwendbarer Bausteine. Design-Tokens als einzige Wahrheitsquelle für Farben, Abstände und Radien verhindern hart kodierte Werte in Komponenten und ermöglichen Theming ohne Neukompilierung. Die Komponenten-API sollte von Beginn an auf Stabilität ausgelegt sein, mit begrenztem Wertebereich für Props und Slots für flexible Inhalte statt beliebiger externer CSS-Injektion.
Vue als peerDependency, ein Build mit ESM- und CommonJS-Ausgabe sowie Subpath-Exports für Tree-Shaking bilden das technische Fundament. Semantic Versioning mit klarer Breaking-Change-Kommunikation, automatisierte Storybook-Dokumentation mit visuellen Regressionstests und ein definierter Governance-Prozess sind am Ende genauso entscheidend wie die Codequalität der einzelnen Vue-Komponenten.
Design System mit Vue-Komponenten — Das Wichtigste auf einen Blick
Design-Tokens
Einzige Wahrheitsquelle für Farben und Abstände, generiert über Style Dictionary in CSS-Variablen.
Komponenten-API
Begrenzte, semantische Props statt beliebiger externer CSS-Klassen, Slots für Inhalte.
Versionierung
Semantic Versioning mit Changesets, Codemods für Major-Releases erleichtern Migrationen.
Dokumentation
Storybook mit Controls, visuellen Regressionstests und Verwendungsrichtlinien.