# mittwald Flow — Full documentation > Full-text Markdown export of the Flow design system documentation, generated for LLMs. The React components are published as `@mittwald/flow-react-components`. Source: https://github.com/mittwald/flow Individual pages are also available by prefixing any docs path with `/raw/` and appending `.md`. --- # Installation --- # Installation der Flow React Component Library Die Flow React Component Library kann mit einem Package Manager wie `npm` oder `yarn` installiert werden. ```shell yarn add @mittwald/flow-react-components ``` Zur leichteren Verwaltung der Abhängigkeiten werden alle Components innerhalb diese Packages bereitgestellt. --- # Styles importieren Um die Components-Styles zu verwenden, musst du das Stylesheet importieren. Füge diese Zeile zum Einstiegspunkt deines Projektes hinzu. ``` import "@mittwald/flow-react-components/all.css"; ``` --- # Defaults für Components festlegen Einige Components verhalten sich nach einem Standard, den du für deine gesamte Anwendung festlegen kannst, anstatt ihn an jeder Verwendung zu wiederholen. Dafür umschließt du deine Anwendung mit dem ``: ```tsx ``` Jede einzelne Verwendung bleibt stärker als der Standard: Setzt eine [List](https://flow.mittwald.de/components/list/list) das `disableInitialSuspenseBoundary`-Property an ihrer Datenquelle oder eine [Form](https://flow.mittwald.de/components/react-hook-form/form) das `confirmModalCloseOnUnsavedChanges`-Property, gilt dort dieser Wert. Verschachtelte Provider gelten jeweils für ihren Teilbaum und übernehmen die Werte, die sie nicht selbst nennen. Diese Defaults stehen zur Verfügung: | Default | Bedeutung | Wert ohne Provider | | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------ | | `List.disableInitialSuspenseBoundary` | Die List rendert beim initialen Laden keine eigene Suspense-Boundary, sondern erscheint erst mit geladenen Daten. | `false` | | `Form.confirmModalCloseOnUnsavedChanges` | Das Schließen eines Modals, das eine Form mit ungespeicherten Änderungen enthält, muss bestätigt werden. | `true` | --- # Aktualisieren Ein Befehl hebt alle Flow-Abhängigkeiten auf die Zielversion, installiert und führt den Codemod jeder Migration bis zu dieser Version aus: ```shell npx @mittwald/flow-codemods@latest upgrade ``` Er ersetzt den Migrationsleitfaden nicht: die meisten Änderungen haben keinen Codemod. Was in deinem Bereich von Hand ansteht, listet der Befehl am Ende auf – vorab und ohne etwas zu verändern zeigt es `list`. Welche Änderung ab welcher Version greift und wie Deprecation-Warnungen den Vorlauf bilden, steht unter [Upgrades](https://flow.mittwald.de/get-started/upgrades). Was Flow dir innerhalb einer Linie zusichert, steht unter [Versionierung & Stabilität](https://flow.mittwald.de/get-started/versioning). --- # Mit KI-Agents arbeiten Ein Coding-Agent liest von sich aus nur die Anweisungen deines Projekts. Diese Dokumentation und die Hinweise im Paket findet er nur, wenn sie dort genannt sind. Füge deshalb diesen Block in die `AGENTS.md` (oder `CLAUDE.md`) deines Projekts ein: ```markdown ## UI mit Flow Bevor du UI mit Flow baust oder änderst: 1. Lies die USAGE.md des Flow-Pakets, das in package.json steht: - `@mittwald/flow-react-components` (Anwendung): node_modules/@mittwald/flow-react-components/USAGE.md - `@mittwald/flow-remote-react-components` (mStudio-Extension): node_modules/@mittwald/flow-remote-react-components/USAGE.md. Importiere dann immer aus diesem Paket, auch wenn die Beispiele der Dokumentation `@mittwald/flow-react-components` zeigen. - `@mittwald/flow-remote-vue-components` (mStudio-Extension in Vue, Beta): node_modules/@mittwald/flow-remote-vue-components/USAGE.md. 2. Lies https://flow.mittwald.de/llms.txt und öffne die dort verlinkte Seite, bevor du eine Component, ein Layout oder einen UI-Text festlegst. Antworte nicht aus dem Gedächtnis. 3. Baust du eine neue App, Seite oder einen Ablauf, wähle zuerst das passende Template aus dem Abschnitt „Templates“ in llms.txt: erst die App-Shell, dann das Seiten-Template, dann Overlays und Bausteine. Starte vom Beispielcode des Templates. Weiche nur davon ab, wenn ausdrücklich ein anderes Layout gewünscht ist – auch bei schnellen Prototypen. ``` Die `USAGE.md` passt zur installierten Version, `llms.txt` beschreibt den aktuellen Stand der Dokumentation und verlinkt jede Seite als Markdown. Auf jeder Seite dieser Dokumentation führt außerdem „Markdowndatei öffnen“ zur Markdown-Fassung. --- # mStudio-Extensions mit Vue (Beta) Eine mStudio-Extension kann statt in React auch in Vue geschrieben werden. Das Package `@mittwald/flow-remote-vue-components` ist das Vue-Gegenstück zu `@mittwald/flow-remote-react-components`: Die Extension rendert damit dieselben Flow Components im mStudio. ```shell FLOW=$(npm view @mittwald/flow-remote-vue-components@next version) yarn add @mittwald/flow-remote-vue-components@$FLOW @mittwald/flow-react-components@$FLOW @mittwald/ext-bridge@$FLOW vue react react-dom ``` `@mittwald/flow-react-components` ist eine Laufzeit- und Typ-Abhängigkeit: Die Remote-Verbindung serialisiert Passwort-Policies über seinen Einstiegspunkt `mittwald-password-tools-js`, der `react` importiert, und die Prop-Typen der Components stammen aus seinen Deklarationen. Fehlt das Package oder `react`, schlägt der Build der Extension fehl, ebenso ohne `@mittwald/ext-bridge`, das `RemoteRoot` importiert. `react-dom` ist eine Peer-Dependency von `@mittwald/flow-react-components`. `yarn` installiert Peer-Dependencies nicht selbst, deshalb stehen alle in der Zeile. Alle Flow-Packages brauchen genau die Version von `@mittwald/flow-remote-vue-components`. Ohne Versionsangabe nehmen pnpm und yarn das `latest`-Tag der beiden anderen, und das ist eine andere Release-Linie. Das Package ist **Beta**. Es ist von der Breaking-Change-Zusage ausgenommen, seine API kann sich auch außerhalb einer Major-Version ändern (siehe [Component Lifecycle](https://flow.mittwald.de/get-started/versioning#component-lifecycle)). Welche Components und Funktionen es schon abdeckt und welche noch fehlen, beschreibt seine [USAGE.md](https://github.com/mittwald/flow/blob/main/packages/remote-vue-components/USAGE.md). --- # Stylesheet Die Flow-Components-Bibliotheken werden über ein gemeinsames Stylesheet, das auch für sich alleine verwendet werden kann, gestyled. Das kann nützlich sein, wenn du dein eigenes Framework verwendest, um Components zu bauen, und dich dabei an die mittwald Styling Guidelines halten willst. Auf dieser Seite findest du alle Informationen darüber, wie du das Stylesheet installieren kannst und wie die Klassennamen strukturiert sind. --- # Installation des Standalone Stylesheets Die Flow-Stylesheet-Bibliothek wird über NPM veröffentlicht und kann mit einem Package Manager wie `npm` oder `yarn` installiert werden. ```shell yarn add @mittwald/flow-stylesheet ``` --- # Styles importieren Um die Components-Styles zu verwenden, musst du das Stylesheet importieren. Füge diese Zeile zum Einstiegspunkt deines Projektes hinzu. ``` import "@mittwald/flow-stylesheet/css"; ``` --- # Layered-Variante (optional) Das Standard-Stylesheet (`@mittwald/flow-stylesheet/css`) ist **ungelayert**: welche Regel gewinnt, entscheidet sich über Spezifität und Quell-Reihenfolge. Optional gibt es eine **gelayerte Variante**, deren Styles in [CSS Cascade Layers](https://developer.mozilla.org/de/docs/Web/CSS/@layer) organisiert sind: ``` import "@mittwald/flow-stylesheet/css-layered"; ``` Aus dem `@mittwald/flow-react-components`-Paket entsprechend: ``` import "@mittwald/flow-react-components/all-layered.css"; ``` Sie liegt unter einem `flow`-Layer mit dieser Reihenfolge: ```css @layer flow.tokens, flow.reset, flow.base, flow.components; ``` - `flow.tokens` – die Design-Token als CSS Custom Properties - `flow.reset` – der globale Reset - `flow.base` – Schriftarten (`@font-face`) und globale Basis-Styles - `flow.components` – die Styles der einzelnen Komponenten --- ## Warum die gelayerte Variante? Nach den Regeln der Cascade Layers gewinnt **ungelayertes** CSS immer gegen gelayertes – unabhängig von der Spezifität. Mit der gelayerten Variante überschreibst du Flows Styles daher ohne `!important` oder Spezifitäts-Tricks: ```css /* Gewinnt gegen Flows .flow--button, ohne !important */ .flow--button { border-radius: 0; } ``` Wenn du selbst mit Cascade Layers arbeitest (z. B. Tailwind), deklariere deine Layer **nach** `flow`, damit sie Vorrang behalten. --- ## Welche Variante wann? - **Standard (`css` / `all.css`):** klassisches, spezifitätsbasiertes Verhalten. Passt auch für Apps mit einem aggressiven globalen Reset (z. B. `* { all: initial }`), der gelayerte Styles sonst vollständig überschreiben würde. - **Layered (`css-layered` / `all-layered.css`):** einfache, spezifitätsfreie Überschreibbarkeit und saubere Interop mit eigenen Cascade Layers. --- # Anwendung des Stylesheets Um anfangen zu können, solltest du verstehen, wie die Klassennamen strukturiert sind. Die im Stylesheet bereitgestellten Klassennamen folgen einem konsistenten, komponentenbasierten und leicht zu verstehendem Schema. --- ## Generelle Klassennamen-Auszeichnungen Alle Klassennamen sind in Lowercase geschrieben und benutzen `-` um Wörter zu trennen und `--` um logische Abschnitte zu unterteilen. Der erste logische Abschnitt ist immer der `flow` Namespace. Andere Abschnitte könnten beispielsweise so aussehen: ### Components ```css .flow--button .flow--heading .flow--alert-badge ``` ### Sub-Components ```css .flow--navigation .flow--navigation--navigation-group ``` ### Spezialisierung: Verschiedene Varianten ```css .flow--button--primary .flow--alert--danger .flow--icon--size-s ``` ### Spezialisierung: In einer Komposition verwendete Components ```css .flow--button--icon .flow--alert--heading ``` --- ## Ein Hinweis zur Spezialisierung Klassennamen die verwendet werden, um die Basiskomponente zu spezialisieren, müssen immer **zusätzlich zum Basis-Klassennamen** verwendet werden. Hier ein paar Beispiele um die diese Anforderung zu verdeutlichen: ```tsx ``` ### Kombinierte Varianten ```tsx ``` ### In einer Komposition verwendete Components Es ist gängige Praxis, größere Components aus bereits bestehenden kleineren Components zusammenzusetzen. Der [Alert](https://flow.mittwald.de/components/status/alert) besteht beispielsweise aus einem [Icon](https://flow.mittwald.de/components/content/icon), einer [Heading](https://flow.mittwald.de/components/content/heading) und optionalem Inhalt. Die verwendeten Components müssen ihren Basis-Klassennamen für das grundsätzliche Styling erhalten (`flow--heading`), sowie den spezialisierten Klassennamen (`flow--alert--heading`), um spezifische Styles des Inline Alerts zu erhalten. ```tsx import ExampleSvg from "@/content/get-started/stylesheet/examples/components/ExampleSvg"; ``` --- # Versionierung & Stabilität --- # Semantic Versioning Alle `@mittwald/flow-*`-Packages teilen sich eine gemeinsame Version. Dieselbe Zusage gilt damit einheitlich für jedes Package. Es gibt keine Package-spezifischen Sonderregeln – ausgenommen ein Package, das als Ganzes Beta ist (siehe [Component Lifecycle](#component-lifecycle)). Seit Version `1.0.0` ist aus einer guten Absicht eine verlässliche Zusage geworden: Wir halten uns an [Semantic Versioning](https://semver.org) und gehen Änderungen planbar und nachvollziehbar an. - **Major** – enthält Breaking Changes. Ein Update kann Anpassungen in deinem Code erfordern. Major-Versionen bleiben bewusst selten. - **Minor** – fügt neue Funktionen hinzu und ist abwärtskompatibel. - **Patch** – enthält Bugfixes und ist abwärtskompatibel. Entscheidend ist die Grenze: Welche Änderung erzwingt eine neue Major-Version, und welche darf in einem Minor oder Patch erscheinen? Die folgenden Abschnitte beschreiben diese Grenze aus Sicht der Entwickler. Wie du ein Update oder eine Migration konkret durchführst, beschreibt [Upgrades](https://flow.mittwald.de/get-started/upgrades). --- # Worauf du dich verlassen kannst Diese Bereiche sind durch die Versionierung geschützt. Eine inkompatible Änderung daran erscheint nur in einer neuen Major-Version: - **Runtime Public API von `public.ts`** – welche Components und Exports existieren und welche Props sie zur Laufzeit akzeptieren, sowie das dokumentierte Verhalten dokumentierter Funktionen. Die Type-Ebene ist hiervon ausdrücklich ausgenommen (siehe unten). - **Components aus `@mittwald/flow-remote-react-components`** – die in mStudio-Extensions verwendete API. Ihre Props sind der Vertrag mit Extension-Entwicklern und unterliegen derselben Zusage. - **Veröffentlichte Icons** – ein Icon zu entfernen oder umzubenennen ist ein Breaking Change. Icons werden ohnehin nie entfernt, sondern nur deprecated. - **Das Remote-Protokoll** – die versionierte Verbindungsschicht zwischen Extension und Host bleibt kompatibel, solange dies möglich ist. Wenn ein Teil der öffentlichen API entfernt werden soll, wird er zunächst als deprecated gekennzeichnet und nicht sofort entfernt. Der alte Pfad bleibt erhalten und wird zur Laufzeit über eine Deprecation-Warnung angekündigt, bevor er in einer Major-Version entfernt wird. Das betrifft die gesamte öffentliche API, nicht nur die in Extensions verwendeten Components. --- # Node- und React-Unterstützung Node und React sind echte Runtime-Voraussetzungen. Auch hier gibt es klare Regeln, welche Änderung eine neue Major-Version erzwingt. **Node** - Der garantierte Node-Floor ist die aktiv unterstützte Node-LTS, aktuell `node >=24`, einheitlich über alle Packages. Er wird nur bei konkretem Bedarf angehoben, nicht um neuen Releases hinterherzulaufen. - Eine Node-Version fallen zu lassen, die noch in ihrem LTS-/Maintenance-Fenster liegt, ist ein Breaking Change (→ Major). Eine bereits End-of-Life-Version fallen zu lassen, darf in einem Minor erscheinen. - Strenger sind die Node-Runtime-Packages `@mittwald/ext-bridge` und `@mittwald/flow-remote-core`: Für sie ist jedes Anheben des Node-Floors ein Breaking Change (→ Major), unabhängig von EOL, und ihr Floor kann konservativer sein als der der übrigen Packages. **React** - Das **Erweitern** der akzeptierten Range (z. B. `^19` → `^19 || ^20`) ist abwärtskompatibel (Minor). - Das **Anheben der Mindestversion** oder das Fallenlassen einer React-Major ist ein Breaking Change (→ Major). --- # Was nicht garantiert ist Damit sich das Design System weiterentwickeln kann, sind die folgenden Bereiche bewusst nicht durch die Versionierung abgedeckt. Sie können sich in jedem Release ändern, auch in einem Minor oder Patch. ## Best-effort TypeScript-Typen, CSS-Klassennamen und Design Tokens fallen nicht unter Semantic Versioning. Eine Änderung daran ist unwahrscheinlich – wir nehmen sie nicht leichtfertig vor –, aber möglich: Sie kann in jedem Release erscheinen, auch in einem Patch, ohne Major-Version und ohne Deprecation-Phase. Wenn du dich auf einen davon stützt, lies „So schützt du dich“. - **TypeScript-Typen.** Das gilt für die gesamte Type-Ebene: Auch das Entfernen oder Umbenennen eines exportierten Typs oder das Verengen eines Prop-Typs ist für sich genommen kein Breaking Change. Nennenswerte Type-Änderungen werden dennoch im Changelog erwähnt. - **CSS-Klassennamen.** Ein internes Implementierungsdetail – weder ihre Existenz noch ihre Schreibweise ist zugesagt. - **Namen und Werte von Design Tokens.** Ein Token kann umbenannt werden, einen anderen Wert bekommen oder verschwinden. ## Ebenfalls nicht abgedeckt - **Das visuelle Erscheinungsbild.** - **Die interne DOM-Struktur.** --- # So schützt du dich Weil die best-effort-Bereiche bewusst nicht garantiert sind, gibt es drei Regeln, an die du dich als Entwickler halten solltest. Drei Regeln für den stabilen Betrieb Style nicht gegen interne CSS-Klassen, referenziere Design Tokens nicht ungeprüft über Releases hinweg, und behandle Flows TypeScript-Typen als best-effort. Alle drei Bereiche ändern sich selten – aber wenn, dann ohne Vorwarnung in einem beliebigen Release. ## Style nicht gegen interne CSS-Klassen Die CSS-Klassennamen der Components sind ein internes Implementierungsdetail und können sich in jedem Release ändern. Verlasse dich für eigenes Styling nicht darauf, dass eine bestimmte interne Klasse existiert oder gleich heißt. Andernfalls kann bereits ein Patch dein Styling brechen. ## Behandle Design Tokens als best-effort Design Tokens sind für die Verwendung innerhalb von Flow gedacht. Greifst du in eigenem Code auf eine Token-CSS-Variable zu, prüfe sie nach einem Update: Name und Wert können sich auch in einem Patch ändern, und ein nicht mehr existierender Token fällt still auf den Browser-Default zurück statt einen Fehler zu werfen. ## Behandle TypeScript-Typen als best-effort Flows TypeScript-Typen folgen nicht Semantic Versioning. Ein `tsc`-Fehler kann daher theoretisch schon in einem Patch auftreten. Wenn ein solcher Bruch für dein Projekt teuer wäre, pinne exakte Versionen (statt `^`-Ranges), sodass ein Update bewusst und kontrolliert erfolgt. Zu einem bewusst herbeigeführten Type-Breaking-Change gehört eine Migrationsnotiz in den Release Notes – so bekommst du einen konkreten Upgrade-Pfad, auch wenn die Änderung in einem Minor oder Patch erscheint. --- # Component Lifecycle Der Vertrag gilt nicht für jede Component gleich. Jede Component hat einen Lifecycle-Status, der die obigen Regeln überschreibt: - **Beta** – von der Breaking-Change-Zusage ausgenommen. Die API kann sich auch außerhalb einer Major-Version ändern. - **Stable** (Standard) – vollständig durch die obigen Regeln gebunden. - **Deprecated** – bis zur Entfernung in einer Major-Version weiter abgesichert und mit einem Migrationspfad versehen. Auch ein ganzes Package kann Beta sein. Das gilt derzeit für `@mittwald/flow-remote-vue-components`, die Vue-Anbindung für mStudio-Extensions: Es teilt die gemeinsame Version, ist aber von der Breaking-Change-Zusage ausgenommen. Die Beta endet, sobald jede seiner bekannten Lücken geschlossen oder als dauerhaft vermerkt ist und seine API feststeht. Ab dann gilt die Zusage auch für dieses Package. Das vollständige Lifecycle-Modell beschreibt [ADR 0003](https://github.com/mittwald/flow/blob/main/docs/adr/0003-component-lifecycle-status.md), Beta für ein ganzes Package [ADR 0007](https://github.com/mittwald/flow/blob/main/docs/adr/0007-beta-packages.md). --- # Upgrades --- # Migration bei einer Breaking Change Jede Änderung, die eine Anpassung in deinem Code erfordert, steht mit Vorher-Nachher-Beispiel im Migrationsleitfaden des betroffenen Packages: - [Migrationsleitfaden @mittwald/flow-react-components](https://github.com/mittwald/flow/blob/main/packages/components/MIGRATION.md) – deckt auch `@mittwald/flow-remote-react-components` ab - [Migrationsleitfaden @mittwald/ext-bridge](https://github.com/mittwald/flow/blob/main/packages/ext-bridge/MIGRATION.md) Die Einträge sind nach Version absteigend sortiert und nennen jeweils die Version, ab der die Änderung greift. Suche die Version, von der du kommst, und arbeite dich nach oben durch. Was dabei überhaupt als Breaking Change zählt und eine neue Major-Version erzwingt, beschreibt [Versionierung & Stabilität](https://flow.mittwald.de/get-started/versioning). ## Nutze die Codemod-CLI Ein Befehl hebt alle Flow-Abhängigkeiten auf die Zielversion, installiert und führt den Codemod jeder Migration bis zu dieser Version aus: ```shell npx @mittwald/flow-codemods@latest upgrade ``` Ohne Argument geht es auf die nächste Minor innerhalb deiner Major. `upgrade patch` bleibt auf deiner Minor, `upgrade major` überquert eine Major-Grenze, und eine exakte Version oder ein Dist-Tag (`next`) gehen genau dorthin. Der Befehl ändert Dateien direkt und bricht auf einem unsauberen Git-Stand ab. Der Befehl kennt keine untere Grenze: er listet auch Migrationen, die vor deiner aktuellen Version erschienen sind. Nichts hält fest, welche davon dein Projekt schon durchgeführt hat – und ein zweiter Durchlauf eines Codemods ändert nichts. Ein Codemod, der durchgelaufen ist, ist allerdings kein Beweis: jeder Codemod ist bewusst eng gefasst und lässt liegen, was er aus dem Code nicht sicher entscheiden kann – ein gespreadetes Prop, eine Component, die über einen eigenen Wrapper re-exportiert wird, ein dynamischer Zugriff. Einen Fehler meldet er dafür nicht. Prüfe nach einem Upgrade deshalb auch die Migrationen mit Codemod am Code nach, nicht nur die ohne. Er ersetzt den Migrationsleitfaden nicht: die meisten Einträge haben keinen Codemod. Welche das für deinen Bereich sind, listet der Befehl am Ende auf – oder vorab, ohne etwas zu verändern, mit `list` und derselben Revision: ```shell npx @mittwald/flow-codemods@latest list minor ``` `list` ohne Argument zeigt den gesamten Katalog, offline. Mit einer Revision liest es dieselbe Version aus deinem `package.json` und zeigt genau den Bereich, den `upgrade` mit dieser Revision anfassen würde – ein echter Trockenlauf. Einen einzelnen Codemod führst du über seine ID aus: ```shell npx @mittwald/flow-codemods@latest align-to-combine src ``` ## Lass einen Agenten das Upgrade machen Was die CLI offen lässt, kann ein Coding-Agent übernehmen: die Migrationen ohne Codemod – das sind die meisten – und die Stellen, die ein Codemod übersprungen hat. `list --json` liefert ihm dafür pro Migration das Feld `apply`: die Anweisung, was zu ändern ist, knapp genug für einen Katalog und präzise genug zum Ausführen. Kopiere den folgenden Prompt in deinen Agenten. Er sucht zuerst, wo Flow überhaupt deklariert ist – in einem Monorepo ist das meist mehr als ein Package, und `list` wie `upgrade` lesen immer nur die `package.json` des Verzeichnisses, in dem sie laufen. Dann klärt er auf, welche Zielversionen zur Wahl stehen und was jede davon an Arbeit bedeutet, und fragt dich, welche es sein soll. Danach geht er jede Migration im Bereich am Code nach – auch die mit Codemod – und ändert nur, wo er das alte Muster wirklich findet. Was dabei offen bleibt, gibt er dir nicht als Hausaufgabe zurück. Genau die Punkte, die eine Entscheidung brauchen, sind die, bei denen er den Diff gelesen hat und du nicht – deshalb legt er sie dir gesammelt vor, jeweils mit den Optionen und einer Empfehlung, setzt deine Antwort um und lässt die Checks erneut laufen. Das wiederholt sich, bis nichts mehr offen ist. Er hört vorher nur auf, wenn etwas wirklich nicht hier entschieden werden kann – eine Design-Entscheidung, eine Freigabe, ein Zugang – und sagt dann, worauf es wartet und wer es tun muss. Der Prompt ist englisch, weil alles, worauf er zeigt, englisch ist: die CLI-Ausgabe, die `apply`-Felder und der Migrationsleitfaden. ```text Upgrade this project's mittwald Flow dependencies. First find out where Flow is declared. Search every `package.json` in the project for a `@mittwald/flow-` dependency, but only the ones the project actually maintains. `git ls-files "*package.json"` gets that right in one step: `node_modules` and build output — `dist`, `build`, `.next`, `.output`, `.nuxt`, `.svelte-kit`, `.turbo`, `out`, `coverage`, whatever this project emits — are git-ignored, and a copied or generated manifest in there would have you upgrading an artefact. Outside a git checkout, exclude those paths yourself. In a monorepo Flow is usually declared in several workspace packages, and the root often declares none. Every command below reads and writes exactly one `package.json`: the one in the directory you run it from. Neither `list` nor `upgrade` walks a workspace, so a single run at the root silently leaves every other package behind. Tell me which packages you found, and which Flow version each is currently on. Then plan — change nothing yet. From one of those packages, run all three and read the JSON: - `npx @mittwald/flow-codemods@latest list patch --json` - `npx @mittwald/flow-codemods@latest list minor --json` - `npx @mittwald/flow-codemods@latest list major --json` Each run reports the version it would resolve to (`range.target`) and every migration in that range. A relative revision only resolves if such a release exists: from a prerelease, or from the newest version on a line, `patch` and `minor` exit non-zero with no JSON and a message saying so. That is not an error to work around — it means the choice is narrower than three options. So show me what actually resolved, side by side: target version, how many migrations carry a codemod, how many need a hand. If fewer than three resolved, say which and why, and put a dist-tag (`next`) or an exact version (`1.4.0`) on the table as an equal option rather than a fallback — those always resolve. Then ask me which target to take, and wait for my answer. Then, on the target I chose: - Commit or stash what is open first. Do not pass `--allow-dirty` — that guard is what keeps a bad run `git checkout`-able. - Run `npx @mittwald/flow-codemods@latest upgrade `. It bumps the dependencies, installs, and runs the codemod of every migration up to the target. Pass `--path ` unless the sources really are under `./src` — find that directory before the first command, not after. - It bumps every package published from the Flow monorepo, not only the `@mittwald/flow-*` ones: `@mittwald/ext-bridge`, `@mittwald/mstudio-ext-react-components` and `@mittwald/react-tunnel` are on the same release train and move too. Tell me which ones it actually rewrote. - Only if more than one package declares Flow: run it once per package, from that package's own directory, passing the resolved exact version rather than `patch`/`minor`/`major` — a relative revision resolves from the version that one package is on, so packages that started out apart would land apart. And commit after each one: the dirty-tree guard reads `git status` for the whole repository, so the second run would otherwise refuse. Do not reach for `--allow-dirty` instead; committing keeps each package a revertible step. - `peerDependencies` are reported and deliberately left untouched. Note what it named as an open decision for the closing round below — do not hand it to me now and do not narrow a range on your own. That report comes after the install, so a failed install means you never see it; read the manifests yourself then. - If the install fails with `ETARGET` or `ERR_PNPM_NO_MATCHING_VERSION` on a Flow package, that is the publishing window right after a release. Wait a few minutes and install again — do not pin anything and do not mix Flow versions to get around it. - If the install fails for any other reason, do not wait and retry — that only helps the case above. The manifest is already rewritten while `node_modules` still holds the old version, so read the actual error and finish the install yourself with the project's own package manager. The command detects the manager from lockfiles in the directory it runs in, which in a workspace package is the wrong place to look: check the repository root for a lockfile and a `packageManager` field before trusting what it chose. Confirm the versions it wrote are published, then install; revert the bump only if they are not. Then check every migration against the code — every entry in the JSON, including the ones with `action: "codemod"`. A codemod is deliberately scoped narrowly and skips anything it cannot decide from the source: a spread prop, a component re-exported through a local wrapper, a dynamic access, a file outside the path it ran on. It reports no error for those. A codemod that ran clean is therefore not proof the old pattern is gone — treat its run as a head start, not as a result. Read the `upgrade` report for what it admits: an entry that changed no file, declined every file it looked at, or found nothing to process is the strongest hint that its pattern is still there in a shape it could not handle. One caveat on that report. "No files were processed. Is the path right?" is also what a codemod that crashed before touching a file looks like — the counters are identical, and the summary line guesses at the path. Check stderr for a stack trace before you believe the path is wrong, and tell me if a codemod died: its migration then had no run at all, and everything below is the only thing that covers it. Include the entries flagged `catchUp: true`. They shipped before the version this project was on and may never have been done here. For each entry: 1. Read `apply`. It is the whole instruction — the JSON carries no example, and the human-readable `list` output has none either. For a before/after example, look up the entry id in `MIGRATION.md`, which ships inside `@mittwald/flow-react-components` and is also on GitHub. Do not paste the command `list` prints beside an entry: its path argument is hardcoded to `src`, which is wrong wherever `--path` was needed above. 2. Search for the old pattern across every package that uses Flow, not just the one you last ran in. Resolve Flow imports properly — named, aliased and namespace imports all count — and treat an entry marked `remotePackage: true` as applying to `@mittwald/flow-remote-react-components` too. 3. No match: say so and move on. No edit. 4. Match: make the change `apply` describes, by hand. On a codemod entry, do not just run the codemod again — it already saw that site and declined it, so a second run declines it again. 5. Leave an edit undone only when the right migration is genuinely ambiguous from the code. Do not hand it to me here: record it as an open decision with the entry id, the site, the options you see and which one you would pick and why. The closing round below settles it. Keep the change scoped to the upgrade. No unrelated refactoring, no reformatting of files you did not otherwise touch. Then run the project's own checks — type check, lint, build, tests, whatever `package.json` provides — and fix what the upgrade broke. In a monorepo run them at the root so a package you did not touch is covered too: a Flow change in one package can break its consumer in another. A failure that was already there before the upgrade is not yours to fix, and not mine to be handed either. Check it against the commit you started from, then say which of the two it is. Pre-existing ones: name them in one line each and leave them alone — chasing them turns an upgrade into an open-ended cleanup. If the project has no checks at all, say that too, so neither of us mistakes silence for a green run. Then finish the migration with me. Do not hand me a list of leftovers — a migration that ends in homework is not done, and the open items are exactly the ones where you have the context and I do not, having not read the diff. Go through every open decision you recorded, plus the `peerDependencies` report, one at a time. For each: name the entry and the site, show the code as it stands, lay out the options in a sentence each, say which one you would pick and why, and ask me. Ask them in one pass rather than trickling them out, and put the ones that block a check first. If a decision turns out to have one obviously right answer once you look properly, take it and tell me — do not spend my attention on a question you can answer. Apply each answer as I give it, then run the checks again: a decision can break something the previous pass did not touch, and closing one item can make another moot. Repeat until nothing is open. Stop only when one of these is true, and say which: - Nothing is open. Every check that passed before the upgrade passes again — or the project has none — and no decision is waiting. - What is left genuinely cannot be settled here — it needs someone who owns the design, an approval, a credential, or a change outside this upgrade's scope. Name each one, say exactly what it is waiting on and who has to do it, and put it in a state I can pick up: the code compiling, or a single clearly marked spot to come back to. - I told you to stop. Then summarize: which packages you upgraded and from which version to which, which codemods changed files, which entries you fixed by hand, which found nothing, what we decided together — and whether anything is still open, with the reason from the list above. If nothing is open, say so plainly rather than padding the summary with caveats. Finally, do not leave the whole migration sitting uncommitted. Walk me through the diff at the level of what changed and why — not file by file — then propose how to commit it: one commit, or one per package in a monorepo, with the messages written out. Commit once I say so. If I would rather review first, leave the tree as it is and say so in one line; do not commit without an answer, and do not push in any case. ``` Zwei Dinge, die der Prompt bewusst nicht tut: Er lässt den Agenten nicht auf einem unsauberen Git-Stand starten, damit ein missglückter Lauf ein `git checkout` bleibt. Und er lässt ihn nichts an deinen `peerDependencies` ändern – was deine eigenen Consumer installieren dürfen, ist deine Entscheidung. ### Optional: erzähl uns, was nicht getragen hat Ganz unabhängig vom Upgrade: der folgende Prompt ist ein **zweiter, eigener Baustein**. Du kopierst ihn – wenn du magst – direkt nach dem Upgrade in dieselbe Session. Der Agent hat den Lauf dann noch im Kontext und schreibt daraus einen Bericht auf zwei Ebenen. Nicht kopieren ist die Absage; am Upgrade ändert das nichts. **Der Prompt selbst.** Ein Schritt in der falschen Reihenfolge. Eine Annahme, die auf dein Projekt nicht zutrifft. Eine Stelle, an der der Agent raten musste oder zwei Anweisungen sich widersprachen. Eine Situation, zu der der Prompt schweigt. Eine Anweisung, die Arbeit gekostet und nichts geändert hat. **Die einzelne Migration.** Ein `apply`, das ohne Raten nicht ausführbar war. Eine Stelle, die ein Codemod liegen gelassen hat, obwohl er sie hätte entscheiden können. Eine Migration ohne Codemod, die mechanisch entscheidbar wäre. Ein `apply`, das eine Umbenennung beschreibt, obwohl sich auch die Signatur geändert hat. Ein Codemod, der abgestürzt ist. Und der wertvollste Fall: ein Bruch, den deine Checks gefunden haben und für den es gar keinen Katalogeintrag gibt. Beide Ebenen sehen wir sonst nicht. Ob eine Migration verständlich beschrieben ist und ob der Upgrade-Prompt trägt, zeigt sich erst an einer echten Codebase – nicht an unserer. Ein Bericht als [Issue](https://github.com/mittwald/flow/issues) hilft uns deshalb wirklich weiter: er fließt in den Katalog und in den Prompt zurück, und das nächste Upgrade ist für alle etwas weniger Handarbeit. Ein Paste genügt, und eine Antwort schuldest du niemandem. Der Agent reicht ihn nicht selbst ein. Er legt ihn dir vor und sagt dir, was du damit tun kannst – du entscheidest, was rausgeht. Code-Beispiele reduziert er auf die kleinste anonymisierte Form, aber prüfen musst du das selbst. ```text Write a report on that upgrade for Flow's maintainers — not for me. Report where their tooling fell short, not what my project needed. Judge every point from what actually happened in this session, not from reading any text back: a plausible-sounding critique nobody hit is worse than no report, because it sends them after a problem that does not exist and nothing here can be checked against anything. It has two parts, and the first is the one nobody ever sends. Part one, the upgrade prompt you just followed. You ran it end to end against a codebase its authors have never seen, which is the only way its gaps show up at all. Report: - A step that came in the wrong order, or that assumed something this project does not have. - A point where you had to guess what was meant, or where two instructions pulled in different directions. - A situation you ran into that the prompt says nothing about, and what you did instead. - An instruction that turned out to be unnecessary, or that cost work without changing the outcome. - What you would have wanted to know before you started. Part two, the migration catalogue. Name the entry id for each: - Entries whose `apply` you could not execute without guessing. Quote the field and say what it left open. - Sites a codemod declined that it looks like it could have handled. Name the shape that defeated it. - Entries with `action: "manual"` whose change looks mechanically decidable — a codemod could exist there and does not. - Breaks the checks surfaced that no entry in the catalogue covers at all. These matter most: nothing else reveals them. - An `apply` that described a rename but was also a type or behaviour change, or that contradicted the code you actually saw. - A codemod that crashed, or a command the tool printed that did not work as printed. Write it as Markdown that can go into an issue unedited, opening with the version you went from and to, the package manager, and whether this is a monorepo. Reduce every code sample to the smallest anonymised shape that still shows the problem: no project or package names, no file paths, no business logic. If a point has nothing under it, drop the point rather than padding it; if a whole part would be empty, say so in one line. Do not file it anywhere and do not push it. Hand it over, and close by telling me what I can do with it: - Send it as a new issue at https://github.com/mittwald/flow/issues. This is genuinely valuable to the Flow team — a run against a codebase they cannot see is the only way they learn where the catalogue and that prompt fall short, and what comes back feeds into both. It takes one paste. - Or drop it. Nothing depends on it and no answer is owed. Either way the choice is mine, and so is the review: tell me to read it for anything about my project I would not put in a public tracker before I send it. ``` ## Deprecation-Warnungen sind der Vorlauf Wird ein Pfad deprecated, bleibt er funktionsfähig und meldet sich zur Laufzeit per `console.warn`. Diese Warnungen sind die Vorwarnzeit vor der nächsten Major-Version – behandle sie als Aufgabenliste, nicht als Rauschen. Um sie zentral einzusammeln, etwa im Error-Tracking, umschließe deine Anwendung mit einem `DeprecationWarningProvider` und gib ihm einen `onWarning`-Handler: ```tsx reportToTracking(message)}> ``` --- # Direkt nach einem Release Ein Release veröffentlicht die Packages **nacheinander**, nicht gleichzeitig. Für einige Minuten liegt in der npm-Registry deshalb für die schon veröffentlichten Packages die neue Version, für die restlichen noch die alte. Beim Release `1.0.6` lagen zwischen dem ersten und dem letzten Package rund 25 Minuten. Du triffst dieses Fenster leicht, denn ein Update betrifft immer mehrere Packages: alle `@mittwald/flow-*`-Packages teilen sich eine gemeinsame Version, und `@mittwald/flow-react-components` fordert `@mittwald/flow-icons-pro` als Peer-Dependency in exakt derselben Version. Ziehst du in diesem Fenster alle Flow-Abhängigkeiten auf die neue Version, schlägt die Installation für das Package fehl, das noch nicht dran war: ``` npm error code ETARGET npm error notarget No matching version found for @mittwald/flow-react-components@1.0.6 ``` pnpm meldet dasselbe als `ERR_PNPM_NO_MATCHING_VERSION`. Das ist keine Lücke im Release: sobald der Release-Lauf durch ist, haben alle Packages dieselbe Version. Direkt nach einem Release ist dieser Fehler fast immer das Veröffentlichungsfenster und nichts anderes. Warte ein paar Minuten und installiere erneut Das Fenster schließt sich von selbst. Du brauchst keinen Workaround – pinne nichts fest und mische keine Flow-Versionen, um den Fehler zu umgehen. --- # Releases Diese Seite bündelt die veröffentlichten Flow-Releases in einer Zeitleiste – mit Highlights, Migrationshinweisen und den enthaltenen Fixes je Patch-Version. Wie du ein Update einspielst, beschreibt [Upgrades](https://flow.mittwald.de/get-started/upgrades). --- # Design Tokens Design Tokens übersetzen grundlegende Designentscheidungen wie Farben, Abstände und mehr in eine einheitliche Sprache. Entwickler und Designer nutzen diese Sprache, um ein konsistentes, skalierbares und wiederverwendbares Design in der gesamten Benutzeroberfläche sicherzustellen. --- # Was sind Design Tokens? Ein Design Token (kurz: Token) besteht aus 2 Teilen: Name und Wert. Der Name eines Tokens folgt einem klaren und verständlichen Benennungsschema. Der Wert kann alles beinhalten, was zum Erstellen eines Designs notwendig ist: Eine Farbe in RGB, eine Schriftart, eine Animations-Geschwindigkeit oder einen anderen Token. --- # Vorteile - **Verringerter Wartungsaufwand:** Tokens können aufeinander basieren und die Eigenschaften eines anderen Tokens erben. Dadurch wirken sich Änderungen an einem Token-Wert automatisch auf alle Stellen aus, an denen er verwendet oder referenziert wird. Das spart Zeit und reduziert Fehler. - **Verbesserte Zusammenarbeit:** Design und Development nutzen mit Tokens eine gemeinsame Sprache. Dadurch lassen sich Designentscheidungen leicht verständlich ausdrücken und ebenso einfach im Code implementieren. - **Einheitliches Design:** Farben, Schriften, Größen und mehr werden überall einheitlich verwendet. - **Wiederverwendbarkeit:** Tokens lassen sich problemlos in mehreren Projekten und Frontends gleichzeitig verwenden. --- # Benennung von Tokens Unsere Tokens sind leicht verständlich und nachvollziehbar benannt, um komplexe Informationen konsistent und selbsterklärend zu vermitteln. ## Schema Jeder Token-Name folgt einem dreistufigen Benennungsschema: Context, Common Unit und Clarification. Dieses Schema beginnt mit einer allgemeinen Einordnung und wird von Stufe zu Stufe immer detaillierter. **ℹ️ Token-Benennungsschema** ```tsx import { Badge, ColumnLayout, Text, } from "@mittwald/flow-react-components"; Context Einordnung
z. B. Farbe, Component
Common Unit Kategorie
z. B. Variante, Sizing, Styling
Clarification Spezifizierung
z. B. Farbwert, State
``` ### Context Der Context stellt den allgemeinsten Zusammenhang dar, auf den ein Token sich beziehen kann. ### Common Unit Die Common Unit ordnet den Token in eine spezifische Kategorie innerhalb des Context ein. ### Clarification Die Clarification ist die präziseste Ebene, die den Token klar definiert und abgrenzt. ## Beispiele **color--hosting-blue--800** Der Token `color--hosting-blue--800` definiert eine spezifische [Color](https://flow.mittwald.de/foundations/design/colors). `color` gibt den **Context** an. Der Name der Farbe `hosting-blue` ist die **Common Unit**. Die Zahl `800` ist die **Clarification**, die die Abstufung der Farbe definiert und auf den genauen Farbwert `#0054F5` im Designsystem verweist. **primary-solid-background-color--default** Dieser Token definiert die primäre Hintergrundfarbe einer „Solid“-Variante. `primary` gibt als Context an, dass es sich um eine primäre Farbe handelt. Die Common Unit `solid-background-color` verdeutlicht, dass die Farbe als Hintergrundfarbe in der „Solid“-Variante verwendet wird. Die **Clarification** `default` gibt an, dass der Token für den Default-State verwendet wird. **alert--info-border-color** Dieser Token definiert eine Designentscheidung für eine spezifische Component, in diesem Fall einen [Alert](https://flow.mittwald.de/components/status/alert). `alert` liefert den **Context** und stellt klar, dass der Token nur für diese Component verwendet wird. `info-border-color` als **Common Unit** kategorisiert den Token weiter ein: Er wird für die Border-Color eines Alerts in der „Info“-Variante verwendet. Eine **Clarification** braucht dieser Token nicht, weil die Border-Color eines Alerts in allen States gleich bleibt. --- # Token-Arten und Struktur Im Benennungsschema haben wir bereits Tokens mit unterschiedlicher Komplexität betrachtet. In diesem Abschnitt erklären wir die Konzepte, die den verschiedenen Token-Arten und deren Struktur zugrunde liegen. ## Global Token Diese Tokens bilden die Grundlage des gesamten Designsystems. Sie definieren grundlegende Eigenschaften wie Farben, Schriftarten und Abstände, die überall im System verwendet werden können. Global Tokens sollten nur eingesetzt werden, wenn der Verwendung kein tieferes Konzept zugrunde liegt. Ein gutes Beispiel dafür sind Farben, die einen rein dekorativen Zweck erfüllen. Diese müssen nicht weiter definiert oder in eine Kategorie eingeordnet werden, da sie einen rein optischen Nutzen erfüllen und keiner tieferen Idee folgen. | Token-Name | Wert | | ------------------------ | ------- | | color--hosting-blue--800 | #0054F5 | | size-px--s | 8px | ## Alias Token Alias Tokens referenzieren andere Tokens und weisen ihnen eine spezifischere Bedeutung zu. Sie helfen dabei, allgemeine Werte in spezifischen Kontexten einzusetzen. Ein Alias Token konkretisiert z. B. bei einer Color, in welchem Zusammenhang (Primary, Success, Danger, ...) sie genutzt werden soll. Sie beziehen sich immer auf einen Global Token und dürfen keine hard coded Werte besitzen. Wir nutzen diese Ebene vor allem für die Definition von Tokens, die sich keiner bestimmten Variante (Solid, Soft, Outlined, Plain) zuordnen lassen, aber in eine gemeinsame Kategorie zusammengefasst werden können. | Token-Name | Wert | | ------------------- | ------------------------ | | primary--color--800 | color--hosting-blue--800 | | border-width--400 | size-px--s | ## Alias Token 2 Tokens dieser Ebene besitzen einen noch höheren Detailgrad. Sie werden oft einer spezifischen Variante zugeordnet und fügen weitere Details hinzu, die über den ersten Alias Token hinausgehen. Dabei achten wir auch darauf, die Token so zu definieren, dass sie innerhalb der Variante gut harmonieren. So legen wir z. B. bei einer bestimmten Variante die Farben so fest, dass die Content-Farbe optisch zur Hintergrundfarbe passt und barrierefrei lesbar ist. Ein Alias Token 2 darf keine hard coded Werte besitzen, sich aber sowohl auf Alias als auch Global Token beziehen. | Token-Name | Wert | | --------------------------------------- | ------------------- | | primary-solid-background-color--default | primary--color--800 | | info-outline-border-color | info--color--800 | ## Component Specific Token Diese Tokens sind speziell auf einzelne Components zugeschnitten. Sie vermitteln einzigartige Designentscheidungen, die ausschließlich für eine bestimmte Component relevant sind. Sie enthalten den höchsten Detailgrad der Token-Struktur und sind somit das Gegenteil eines Global Tokens. | Token-Name | Wert | | ----------------------------------------------- | --------------------------------------- | | button--primary-solid-background-color--default | primary-solid-background-color--default | | alert--info-border-color | info-outline-border-color | --- # Color Ausgewählte Colors verkörpern die Marke und dienen gleichzeitig als wesentliches Kommunikationsmittel in der Benutzeroberfläche. Sie lenken die Aufmerksamkeit des Users und vermitteln gezielt wichtige Informationen wie z. B. den Status. --- # Base Color Base Colors bilden das Fundament des Flow Design Systems. Sie prägen die Oberflächen und schaffen die visuelle Grundlage für alle Components und Layouts. ## Neutral Color Neutral Colors sind zurückhaltend und vielseitig einsetzbar. Durch ihre Ausgewogenheit harmonieren sie mit allen weiteren Farben und kommen in nahezu allen UI-Elementen zum Einsatz. | Token | Wert | | --- | --- | | `--color--gray--100` | `#FFFFFF` | | `--color--gray--200` | `#F4F8FC` | | `--color--gray--300` | `#E5EFF8` | | `--color--gray--400` | `#DCE9F7` | | `--color--gray--500` | `#B7C9DB` | | `--color--gray--600` | `#8FA1B4` | | `--color--gray--700` | `#5E6C7A` | | `--color--gray--800` | `#3A434E` | | `--color--gray--900` | `#292F37` | | `--color--gray--1000` | `#1B1F24` | | `--color--gray--1100` | `#121518` | | `--color--gray--1200` | `#000000` | ## Hosting Blue Hosting Blue ist unsere Primärfarbe. Sie verleiht dem mStudio ein prägnantes Erscheinungsbild und stärkt die Wiedererkennung der Marke mittwald. Aufgrund ihrer Leuchtkraft eignet sie sich besonders für gezielte Akzente, interaktive Elemente und visuelle Hervorhebungen. | Token | Wert | | --- | --- | | `--color--hosting-blue--100` | `#F0F5FF` | | `--color--hosting-blue--200` | `#E0EBFF` | | `--color--hosting-blue--300` | `#ABC6FF` | | `--color--hosting-blue--400` | `#85AFFF` | | `--color--hosting-blue--500` | `#6197FF` | | `--color--hosting-blue--600` | `#3D80FF` | | `--color--hosting-blue--700` | `#1A68FF` | | `--color--hosting-blue--800` | `#0054F5` | | `--color--hosting-blue--900` | `#003FB8` | | `--color--hosting-blue--1000` | `#002A7B` | | `--color--hosting-blue--1100` | `#00205C` | --- # Functional Color Functional Colors kommunizieren Zustände und unterstützen die Nutzerführung. Sie helfen dabei, Informationen schnell einzuordnen und Handlungsbedarf zu erkennen. Weitere Details zur Anwendung finden sich im [Informationskonzept](https://flow.mittwald.de/foundations/content-guidelines/informationskonzept). ## Espelkamp Green Espelkamp Green steht für positive Rückmeldungen und erfolgreiche Aktionen. Die Farbe signalisiert Bestätigung, Abschluss oder einen fehlerfreien Zustand. | Token | Wert | | --- | --- | | `--color--espelkamp-green--100` | `#DCFFF4` | | `--color--espelkamp-green--200` | `#C0FFEB` | | `--color--espelkamp-green--300` | `#87FFDA` | | `--color--espelkamp-green--400` | `#4FFFC9` | | `--color--espelkamp-green--500` | `#17FFB8` | | `--color--espelkamp-green--600` | `#00DE9A` | | `--color--espelkamp-green--700` | `#00A673` | | `--color--espelkamp-green--800` | `#00825B` | | `--color--espelkamp-green--900` | `#005F42` | | `--color--espelkamp-green--1000` | `#003B29` | | `--color--espelkamp-green--1100` | `#00291C` | ## Royal Orange Royal Orange kennzeichnet Warnungen und weist auf potenzielle Risiken oder unerwünschte Zustände hin. Die Farbe signalisiert, dass Aufmerksamkeit erforderlich ist und eine Handlung zeitnah erfolgen sollte, auch wenn noch kein kritischer Fehler vorliegt. | Token | Wert | | --- | --- | | `--color--royal-orange--100` | `#FFF4EB` | | `--color--royal-orange--200` | `#FFEBDC` | | `--color--royal-orange--300` | `#FFD9BD` | | `--color--royal-orange--400` | `#FFC89F` | | `--color--royal-orange--500` | `#FFA562` | | `--color--royal-orange--600` | `#FF9343` | | `--color--royal-orange--700` | `#FF8225` | | `--color--royal-orange--800` | `#F56800` | | `--color--royal-orange--900` | `#C25200` | | `--color--royal-orange--1000` | `#8F3D00` | | `--color--royal-orange--1100` | `#763200` | ## Amaranth Red Amaranth Red kennzeichnet kritische Zustände. Die Farbe signalisiert dringenden Handlungsbedarf oder Fehler, die unmittelbare Aufmerksamkeit erfordern. | Token | Wert | | --- | --- | | `--color--amaranth-red--100` | `#FDF0F3` | | `--color--amaranth-red--200` | `#FBE0E6` | | `--color--amaranth-red--300` | `#F7C1CC` | | `--color--amaranth-red--400` | `#F2A2B3` | | `--color--amaranth-red--500` | `#EE8299` | | `--color--amaranth-red--600` | `#EA637F` | | `--color--amaranth-red--700` | `#E54366` | | `--color--amaranth-red--800` | `#E1244C` | | `--color--amaranth-red--900` | `#AB1737` | | `--color--amaranth-red--1000` | `#710F24` | | `--color--amaranth-red--1100` | `#540B1B` | --- # Decorative Color Decorative Colors erweitern die Farbpalette um zusätzliche Markenfarben. Sie werden ausschließlich für dekorative Elemente sowie für Marketing- und Kommunikationsmaßnahmen eingesetzt und haben keine funktionale Bedeutung innerhalb des Interfaces. ## Soft Contrast Violet | Token | Wert | | --- | --- | | `--color--soft-contrast-violet--100` | `#F4F3FE` | | `--color--soft-contrast-violet--200` | `#EAE7FD` | | `--color--soft-contrast-violet--300` | `#D6D0FA` | | `--color--soft-contrast-violet--400` | `#C2B9F8` | | `--color--soft-contrast-violet--500` | `#AEA2F5` | | `--color--soft-contrast-violet--600` | `#998BF3` | | `--color--soft-contrast-violet--700` | `#8574F0` | | `--color--soft-contrast-violet--800` | `#715DEE` | | `--color--soft-contrast-violet--900` | `#5d4abf` | | `--color--soft-contrast-violet--1000` | `#483b9f` | | `--color--soft-contrast-violet--1100` | `#302a6f` | ## Super Teal | Token | Wert | | --- | --- | | `--color--super-teal--100` | `#ebfdff` | | `--color--super-teal--200` | `#cffaff` | | `--color--super-teal--300` | `#96f3ff` | | `--color--super-teal--400` | `#5eedff` | | `--color--super-teal--500` | `#26e7ff` | | `--color--super-teal--600` | `#00d3ed` | | `--color--super-teal--700` | `#00a1b5` | | `--color--super-teal--800` | `#008696` | | `--color--super-teal--900` | `#006b78` | | `--color--super-teal--1000` | `#004f59` | | `--color--super-teal--1100` | `#00424a` | ## Bright Lilac | Token | Wert | | --- | --- | | `--color--bright-lilac--100` | `#f9e9ff` | | `--color--bright-lilac--200` | `#f6dfff` | | `--color--bright-lilac--300` | `#f1caff` | | `--color--bright-lilac--400` | `#ebb6ff` | | `--color--bright-lilac--500` | `#e6a1ff` | | `--color--bright-lilac--600` | `#e08dff` | | `--color--bright-lilac--700` | `#ce4bff` | | `--color--bright-lilac--800` | `#bc08ff` | | `--color--bright-lilac--900` | `#9000c5` | | `--color--bright-lilac--1000` | `#5f0083` | | `--color--bright-lilac--1100` | `#470062` | ## mittwald Navy | Token | Wert | | --- | --- | | `--color--mittwald-navy--100` | `#E4E7F6` | | `--color--mittwald-navy--200` | `#C8CFEE` | | `--color--mittwald-navy--300` | `#A5B0E2` | | `--color--mittwald-navy--400` | `#8291D7` | | `--color--mittwald-navy--500` | `#5F73CC` | | `--color--mittwald-navy--600` | `#3D55C1` | | `--color--mittwald-navy--700` | `#32459E` | | `--color--mittwald-navy--800` | `#27367B` | | `--color--mittwald-navy--900` | `#1D285C` | | `--color--mittwald-navy--1000` | `#131B3D` | | `--color--mittwald-navy--1100` | `#0E142E` | --- # Light und Dark Color Light und Dark Colors wurden speziell für den Einsatz auf farbigen Hintergründen oder Bildern entwickelt. Sie bestehen aus jeweils 8 transparenten Abstufungen. Da die Farben auf Transparenzen basieren, muss der Kontrast zur jeweiligen Hintergrundfarbe eigenständig auf Barrierefreiheit geprüft werden. Aus diesem Grund stehen sie nur in definierten Components zur Verfügung, beispielsweise im [Button](https://flow.mittwald.de/components/actions/button). Die Verwendung orientiert sich am HSL-Farbmodell. HSL steht für Hue, Saturation und Lightness. Für die Auswahl von Light oder Dark ist ausschließlich der Lightness-Wert relevant. Er beschreibt die wahrgenommene Helligkeit einer Farbe auf einer Skala von 0 bis 100. Als Schwellenwert gilt 50. Liegt der Lightness-Wert **unter 50**, sollte **Light** verwendet. Liegt der Lightness-Wert **über 50**, sollte **Dark** verwendet. Grundsätzlich gilt: Je weiter der Lightness-Wert vom Schwellenwert 50 entfernt ist, desto größer ist in der Regel der erreichbare Kontrast. Werte deutlich unter 50 verbessern den Kontrast mit Light, Werte deutlich über 50 verbessern den Kontrast mit Dark. Themes berücksichtigen Bei der Verwendung von Light und Dark auf individuellen Hintergründen sollte das Verhalten beim Theme-Wechsel bewusst gesteuert werden. Nutze dafür die Colors Light Static und Dark Static. Mehr zu Themes ## Light Verwende die Light-Color, bei dunklen Hintergründen mit einem HSL Lightness-Wert von weniger als 50. | Token | Wert | | --- | --- | | `--color--white-alpha--100` | `rgb(255 255 255 / 12.5%)` | | `--color--white-alpha--200` | `rgb(255 255 255 / 25%)` | | `--color--white-alpha--300` | `rgb(255 255 255 / 37.5%)` | | `--color--white-alpha--400` | `rgb(255 255 255 / 50%)` | | `--color--white-alpha--500` | `rgb(255 255 255 / 62.5%)` | | `--color--white-alpha--600` | `rgb(255 255 255 / 75%)` | | `--color--white-alpha--700` | `rgb(255 255 255 / 87.5%)` | | `--color--white-alpha--800` | `rgb(255 255 255 / 100%)` | ## Dark Verwende die Dark-Color, bei hellen, farbigen Hintergründen mit einem HSL Lightness-Wert von größer als 50. | Token | Wert | | --- | --- | | `--color--black-alpha--100` | `rgb(0 0 0 / 12.5%)` | | `--color--black-alpha--200` | `rgb(0 0 0 / 25%)` | | `--color--black-alpha--300` | `rgb(0 0 0 / 37.5%)` | | `--color--black-alpha--400` | `rgb(0 0 0 / 50%)` | | `--color--black-alpha--500` | `rgb(0 0 0 / 62.5%)` | | `--color--black-alpha--600` | `rgb(0 0 0 / 75%)` | | `--color--black-alpha--700` | `rgb(0 0 0 / 87.5%)` | | `--color--black-alpha--800` | `rgb(0 0 0 / 100%)` | --- # Categorical Color Categorical Colors eignen sich hervorragend, um Daten optisch in Kategorien zu unterscheiden. Die Farben sind so optimiert, dass sie durch hohe Kontraste auch für Menschen mit einer Farbsehschwäche gut unterscheidbar sind. Am besten funktionieren sie in der hier gegebenen Reihenfolge. **Achtung:** Categorical Colors sind ausschließlich für Datenvisualisierung gedacht und heben sich bewusst von allen anderen Farben im Design System ab. Darum sollten sie nicht für dekorative Zwecke oder andere UI-Elemente verwendet werden. | Token | Wert | | --- | --- | | `--color--categorical--sea-green` | `#0fb5ae` | | `--color--categorical--palatinate-blue` | `#4046ca` | | `--color--categorical--tangerine` | `#f68511` | | `--color--categorical--magenta` | `#de3d82` | | `--color--categorical--tropical-indigo` | `#7e84fa` | | `--color--categorical--malachite` | `#72e06a` | | `--color--categorical--azure` | `#147af3` | | `--color--categorical--violet` | `#7326d3` | | `--color--categorical--yellow` | `#e8c600` | | `--color--categorical--alloy-orange` | `#cb5d00` | | `--color--categorical--green` | `#008f5d` | | `--color--categorical--lime` | `#bce931` | --- # Themes Themes definieren die visuelle Gestaltung einer Anwendung, ohne die zugrunde liegende Struktur oder Semantik zu verändern. Aktuell unterstützt Flow zwei Themes: - Light - Dark Beide basieren auf denselben Design Tokens und Components. Ein Theme ist damit kein separater Modus mit eigener Logik, sondern eine alternative Darstellung derselben UI. --- # Umgang mit Themes Flow stellt die Grundlage für Themes bereit, übernimmt jedoch nicht automatisch das Theme-Handling in der Anwendung. Das Design System stellt bereit: - Design Tokens für Light und Dark - Components, die diese Tokens verwenden Die Anwendung ist verantwortlich für: - Festlegen des aktiven Themes - Umschalten zwischen Themes - Berücksichtigung der Browsereinstellung - Speicherung der Nutzerpräferenz --- # Individuelle Inhalte Bei der Umsetzung sollte besonders auf Stellen geachtet werden, an denen nicht ausschließlich Tokens verwendet werden, zum Beispiel: - Custom Farben und Farbverläufe - Bilder, Illustrationen oder Media Assets Diese Inhalte reagieren nicht automatisch auf Theme-Wechsel und müssen bewusst so gestaltet werden, dass sie in beiden Themes funktionieren. In bestimmten Fällen ist es sinnvoll, dass einzelne UI-Elemente nicht auf einen Theme-Wechsel reagieren. Zum Beispiel, wenn Components auf festen Hintergründen wie Bildern oder Farbverläufen eingesetzt werden, die sich beim Wechsel des Themes nicht verändern. Für solche Szenarien stellt Flow die Farben Light Static und Dark Static bereit. Diese bleiben unabhängig vom aktiven Theme unverändert und sorgen für konsistente Lesbarkeit. Für die Verwendung von Light Static und Dark Static gelten die gleichen Richtlinien wie für [Light und Dark Colors](https://flow.mittwald.de/foundations/design/colors#light-und-dark-color). **ℹ️ Light Theme** ```tsx import { AccentBox, Heading, LayoutCard, Section, Text, } from "@mittwald/flow-react-components"; <>
Nicht Static Die Farben passen sich an das Theme an.
Static Die Farben bleiben in Dark und Light Theme gleich.
``` **ℹ️ Dark Theme** ```tsx import { AccentBox, Heading, LayoutCard, Section, Text, } from "@mittwald/flow-react-components"; <>
Nicht Static Die Farben passen sich an das Theme an.
Static Die Farben bleiben in Dark und Light Theme gleich.
``` --- # Technische Implementierung Das Theme wird über das Attribut `data-theme` auf dem `:root`-Element gesteuert. Verfügbare Werte sind: - `light` - `dark` - `system` Wird kein Theme gesetzt oder explizit `data-theme="system"` verwendet, dient die bevorzugte Browsereinstellung des Nutzers als Grundlage für die Darstellung. ## @teispace/next-themes Für die Verwaltung und das Umschalten des Themes kann @teispace/next-themes verwendet werden. Die Bibliothek übernimmt dabei das Speichern des gewählten Themes und das Setzen des `data-theme` Attributs. ### ThemeProvider Der `ThemeProvider` wird in der Root der Anwendung eingebunden und steuert, wie das Theme im DOM abgebildet wird: ```tsx import { ThemeProvider } from "@teispace/next-themes"; {children}; ``` ### Theme wechseln mit `useTheme` Innerhalb von Client Components kann das Theme über den Hook `useTheme` gesteuert werden: ```ts import { useTheme } from "@teispace/next-themes"; const { theme, setTheme } = useTheme(); ``` #### Verfügbare Werte: - `theme` → aktuelles gesetztes Theme (`light`, `dark`, `system`) - `setTheme("light" | "dark" | "system")` → wechselt das Theme --- # States States beschreiben den Zustand einer Komponente und ihre Reaktion auf Interaktionen. Flow stellt die States für alle Komponenten bereit. --- # Interaktions-States Interaktions-States entstehen, wenn Nutzer mit einer Komponente interagieren. Die Komponenten zeigen sie automatisch an. ## Default Default ist der Ruhezustand einer Komponente, in dem keine Interaktion stattfindet. Alle anderen States bauen visuell auf ihm auf. ```tsx import { Button } from "@mittwald/flow-react-components"; ``` ## Hover Hover zeigt an, dass sich der Mauszeiger über einem interaktiven Element befindet. Der State signalisiert, dass das Element bedienbar ist. Auf Touch-Geräten gibt es keinen Hover, wichtige Informationen dürfen deshalb nie nur im Hover sichtbar sein. ```tsx import { Button } from "@mittwald/flow-react-components"; ``` ## Pressed Pressed zeigt an, dass ein Element gerade gedrückt wird. Das direkte Feedback bestätigt dem Nutzer, dass seine Eingabe angekommen ist. ```tsx import { Button } from "@mittwald/flow-react-components"; ``` ## Focus Focus zeigt an, welches Element gerade per Tastatur angesteuert ist. Der Focus-Ring erscheint nur bei der Bedienung mit der Tastatur und ist für Nutzer, die ohne Maus navigieren, die wichtigste Orientierung. Der Focus darf deshalb nie verloren gehen. Mehr dazu findest du unter [Accessibility](https://flow.mittwald.de/foundations/design/accessibility). ```tsx import { Button } from "@mittwald/flow-react-components"; ``` ## Selected Selected zeigt an, dass eine Option ausgewählt oder aktiv ist. Typische Komponenten sind [Checkbox](https://flow.mittwald.de/components/form-controls/checkbox), [RadioGroup](https://flow.mittwald.de/components/form-controls/radio-group) und [Tabs](https://flow.mittwald.de/components/structure/tabs). ```tsx import { Checkbox } from "@mittwald/flow-react-components"; Newsletter abonnieren ``` --- # Component-States Diese States werden über Properties gesetzt. Sie beschreiben, ob und wie eine Komponente bedient werden kann. ## Disabled Disabled zeigt an, dass ein Element aktuell nicht bedient werden kann. Der Wert eines deaktivierten Felds wird beim Absenden eines Formulars nicht übermittelt. Mache aus dem Kontext klar, warum das Element nicht zur Verfügung steht, damit Nutzer wissen, was sie tun müssen. Neben dem [Button](https://flow.mittwald.de/components/actions/button) lassen sich auch Eingabefelder wie [TextField](https://flow.mittwald.de/components/form-controls/text-field) oder [Checkbox](https://flow.mittwald.de/components/form-controls/checkbox) deaktivieren. ```tsx import { Button } from "@mittwald/flow-react-components"; ``` ## Read-only Nur mit erkennbarem Kontext verwenden Ein Read-only-Feld unterscheidet sich optisch nicht von einem bedienbaren Feld. Aus dem Kontext muss deshalb klar hervorgehen, dass nichts bearbeitet werden kann, zum Beispiel durch eine als Vorschau gekennzeichnete Ansicht. Read-only zeigt einen Wert an, der relevant ist, aber nicht geändert werden kann. Anders als bei Disabled bleibt der Wert gut lesbar, lässt sich markieren und kopieren und wird mit dem Formular übermittelt. Typische Komponenten sind [TextField](https://flow.mittwald.de/components/form-controls/text-field), [Select](https://flow.mittwald.de/components/form-controls/select) und [Rating](https://flow.mittwald.de/components/form-controls/rating). ```tsx import { Label, TextField, } from "@mittwald/flow-react-components"; ``` ## Invalid Invalid zeigt an, dass eine Eingabe fehlerhaft ist. Kombiniere den State immer mit einem `FieldError`, der erklärt, wie Nutzer den Fehler beheben. Wie du gute Fehlermeldungen formulierst, erfährst du unter [Fehlermeldungen](https://flow.mittwald.de/foundations/content-guidelines/fehlermeldungen). ```tsx import { FieldError, Label, TextField, } from "@mittwald/flow-react-components"; Gib eine gültige Domain ein. ``` ## Required Required kennzeichnet ein Pflichtfeld, das ausgefüllt werden muss, bevor ein [Form](https://flow.mittwald.de/components/react-hook-form/form) abgeschickt werden kann. Flow kennzeichnet dabei nicht die Pflichtfelder, sondern die optionalen: Ihr Label erhält automatisch den Zusatz „(optional)“. ```tsx import { Label, TextField, } from "@mittwald/flow-react-components"; ``` ## Indeterminate Indeterminate zeigt an, dass nur ein Teil der untergeordneten Optionen ausgewählt ist. Der State kommt vor allem bei einer [Checkbox](https://flow.mittwald.de/components/form-controls/checkbox) zum Einsatz, die eine [CheckboxGroup](https://flow.mittwald.de/components/form-controls/checkbox-group) oder die Auswahl in einer Liste zusammenfasst. ```tsx import { Checkbox } from "@mittwald/flow-react-components"; Alle Projekte auswählen ``` ## Pending, Succeeded und Failed Diese States geben dem Nutzer Feedback zu einer Aktion, die im Hintergrund läuft: Pending zeigt an, dass die Aktion läuft, Succeeded, dass sie erfolgreich abgeschlossen wurde, und Failed, dass sie fehlgeschlagen ist. Steuere die States über die [Action](https://flow.mittwald.de/components/actions/action)-Komponente. Sie setzt den passenden State automatisch anhand des Verlaufs der Aktion. ```tsx import { Button } from "@mittwald/flow-react-components"; <> ``` --- # Accessibility Accessibility bedeutet, digitale Produkte so zu gestalten, dass möglichst viele Menschen sie nutzen können. Dazu gehören Menschen mit dauerhaften Einschränkungen ebenso wie Personen mit temporären oder situativen Herausforderungen, etwa bei schlechter Beleuchtung oder mit nur einer freien Hand. Gute Accessibility verbessert die Nutzung für **alle**. Unser Design System Flow bildet dafür eine wichtige Grundlage. Die Components bringen bereits zugängliche Interaktionen, eine sinnvolle Struktur und unterstützende Attribute mit. Echte Accessibility entsteht jedoch erst im Zusammenspiel mit der Umsetzung im Produkt. Flow unterstützt dich dabei, ersetzt aber keine bewussten Entscheidungen in deinem Projekt. Die Anforderungen der [Web Content Accessibility Guidelines (WCAG) 2.2 AA](https://www.w3.org/TR/WCAG22/) dienen Flow als Referenz für eine zugängliche Gestaltung. Sie fließen in Components, Patterns und Grundlagen – wie beispielsweise Kontraste – ein und werden kontinuierlich berücksichtigt und weiterentwickelt. --- # Was Flow für dich übernimmt Unsere Components sind so gestaltet, dass sie automatisch viele typische Anforderungen an Accessibility erfüllen. Dazu gehören zum Beispiel: - ausreichende Kontraste - Tastaturbedienbarkeit - unterstützende ARIA-Attribute an geeigneten Stellen - einheitliche Interaktionsmuster und Patterns Wenn du die Components wie vorgesehen verwendest, hast du bereits eine solide Grundlage für Accessibility. --- # Was du selbst beachten solltest Accessibility entsteht erst durch die richtige Verwendung der Components im Produkt. Beachte dabei einige Grundlagen: - **Nutze semantisches HTML:** Verwende strukturelle Elemente wie `header`, `main` oder `footer`, um Bereiche einer Seite eindeutig zu kennzeichnen, statt generischer Container ohne Bedeutung. - **Achte auf eine sinnvolle Struktur der Seite:** Überschriften sollten logisch aufgebaut sein und Inhalte klar gliedern. - **Setze ARIA-Attribute bewusst ein:** ARIA ergänzt Semantik, ersetzt sie aber nicht. - **Formuliere hilfreiche Alternativtexte für Bilder:** Alt-Texte sollten immer den Zweck eines Bildes beschreiben. Dekorative Bilder benötigen keinen Alternativtext. - **Beschrifte interaktive Elemente verständlich:** [Links](https://flow.mittwald.de/components/navigation/link) und [Buttons](https://flow.mittwald.de/components/actions/button) sollten klar sagen, was passiert. - **Prüfe Farbkontraste bei individuellen Anpassungen.** --- # Mehr erfahren Accessibility ist kein Zustand, den man einmal erreicht und dann abhaken kann. Sie sollte während der Entwicklung regelmäßig geprüft und Schritt für Schritt verbessert werden. Flow und die zugehörige Dokumentation bieten dafür eine solide Grundlage und helfen dir, viele Anforderungen frühzeitig zu berücksichtigen. Es lohnt sich dennoch, sich zusätzlich mit den offiziellen Richtlinien vertraut zu machen. Besonders hilfreich sind die [WCAG 2.2 Guidelines](https://www.w3.org/TR/WCAG22/) sowie die [ARIA Authoring Practices Guide (APG)](https://www.w3.org/WAI/ARIA/apg/). Dort findest du konkrete Best Practices, Beispiele für typische Interaktionsmuster und weiterführende Empfehlungen für barrierearme Interfaces. --- # Typography Typography strukturiert den Inhaltsbereich, indem sie eine visuelle Hierarchie schafft. Darüber hinaus erhöht eine gute Typography die Lesbarkeit und stärkt die Marke im Erscheinungsbild. --- Flow nutzt die Schriftfamilie **Inter**, die für Bildschirmdarstellung optimiert ist und auch in kleinen Größen gut lesbar bleibt. Die einheitliche Verwendung sorgt für ein ruhiges, konsistentes Erscheinungsbild. Für Fließtexte wird **Regular**, für Überschriften und Hervorhebungen **Bold** eingesetzt. Eine Zeilenhöhe (line height) von 150 Prozent zur Schriftgröße (font size) verbessert die Lesbarkeit und unterstützt die Barrierefreiheit. Abweichungen sind nur in Ausnahmefällen vorgesehen. Alle Schriftgrößen werden in **REM** definiert. So bleiben Texte skalierbar, reagieren auf Zoom und berücksichtigen individuelle Systemeinstellungen. --- # Schriftgrößen und Hierarchie Eine klare typografische Hierarchie hilft dabei, Inhalte strukturiert und schnell erfassbar zu machen. ## Headings [Headings](https://flow.mittwald.de/components/content/heading) strukturieren Inhalte und definieren Abschnitte. Jede Stufe hat eine semantische Bedeutung und sollte entsprechend eingesetzt werden. H1 ist die oberste inhaltliche Ebene einer Seite. | Preview | REM | Token | | -------------------------------------- | --------- | ----------------------- | | Heading 1 | 2.625 rem | `font-size-heading-xxl` | | Heading 2 | 2 rem | `font-size-heading-xl` | | Heading 3 | 1.5 rem | `font-size-heading-l` | | Heading 4 | 1.25 rem | `font-size-heading-m` | | Heading 5 | 1.125 rem | `font-size-heading-s` | | Heading 6 | 1 rem | `font-size-heading-xs` | --- ## Body ### Text [Text](https://flow.mittwald.de/components/content/text) wird für Fließtexte, Beschreibungen und längere Inhalte verwendet. Small eignet sich für unterstützende oder sekundäre Informationen. Um Inhalte übersichtlich und schnell erfassbar zu gestalten, lassen sich zentrale Informationen durch Bold gezielt hervorheben. | Preview | REM | Token | | --------------------------------------------- | --------- | ------------------ | | Text (Body) | 1 rem | `font-size-text-m` | | Text (Body) | 1 rem | `font-size-text-m` | | Text (Small) | 0,875 rem | `font-size-text-s` | | Text (Small) | 0,875 rem | `font-size-text-s` | ### Links [Links](https://flow.mittwald.de/components/navigation/link) werden je nach Kontext unterschiedlich gekennzeichnet. Freistehende Verlinkungen sind visuell in Bold hervorgehoben, während sie im Fließtext durch Unterstreichung kenntlich gemacht werden. | Preview | REM | Token | | ----------------------------------- | ----- | ------------------ | | Link | 1 rem | `font-size-text-m` | | [Link](https://flow.mittwald.de/components/navigation/link) | 1 rem | `font-size-text-m` | ### Code Für eine technische Darstellung von Code wird die Schrift **Fira Code** eingesetzt. | Preview | REM | Token | | ------- | --------- | ------------------ | | `code` | 0,875 rem | `font-size-text-s` | --- # Layout Das Layout organisiert die Benutzeroberfläche in einer logischen und hierarchischen Struktur, um die Aufmerksamkeit des Users gezielt zu lenken. Dabei werden Elemente wie Header, Navigation und Content-Bereich berücksichtigt. --- # Best Practices Ein Layout fügt verschiedene Elemente der Benutzeroberfläche zu einer logischen Struktur zusammen. Die folgenden Punkte sind hilfreich, um ein gutes Layout zu erstellen: - Ein Layout sollte den Fokus immer auf die Aufgaben des Users legen. - Ein konsistentes Layout hilft dem User, die Website schneller zu verstehen, da nicht ständig neue Layouts erlernt werden müssen. - Der Fokus des Layouts sollte auf dem Content-Bereich liegen, da hier die Hauptaktionen des Users liegen. Achte hier besonders auf die strukturelle Hierarchie und die inhaltlichen Beziehungen des Contents. - Ein Layout sollte immer responsiv sein, damit die Benutzeroberfläche auch auf kleineren Bildschirmen funktioniert. Im Layout ist grade das Zusammenspiel von Header, Side-Navigation und Content-Bereich für die Responsivität relevant. --- # Genereller Aufbau Grob lassen sich die meisten Layouts, die mit Flow erstellt werden können, in 4 Bereiche einteilen: **Header**, **Side-Navigation**, **Content** und **Overlay**. Das Layout innerhalb dieser Bereiche wird durch verschiedene Components und deren Komposition bestimmt. In unseren Components ist das [Spacing](https://flow.mittwald.de/foundations/structure/spacing) bereits integriert. Verschiedene Layouts mit Code zum Kopieren finden sich unter [Code Templates](https://flow.mittwald.de/templates/app-shells/simple-app). **ℹ️ Layout-Aufbau** Grobes Layout einer Seite. Eingeteilt in Header-, Side-Navigation- und Content-Bereich. ```tsx export default () => { const area: React.CSSProperties = { display: "flex", alignItems: "center", justifyContent: "center", padding: "var(--size-px--xs)", backgroundColor: "var(--info-soft-background-color--default)", border: "1px dashed var(--info-soft-content-color)", borderRadius: "var(--corner-radius--s)", }; const vertical: React.CSSProperties = { writingMode: "vertical-rl", transform: "rotate(180deg)", }; const layout: React.CSSProperties = { alignSelf: "stretch", height: "280px", display: "grid", gridTemplateAreas: ` 'header header' 'nav content' `, gridTemplateColumns: "1fr 5fr", gridTemplateRows: "1fr 6fr", gap: "var(--size-px--s)", color: "var(--info-soft-content-color)", fontSize: "var(--font-size-text--s)", }; return (
Header
Content
); } ``` **mStudio Aufbau** Grobes Layout des mStudios. Darstellung mit Primary und Secondary Navigation. ```tsx import { IconMittwald } from "@mittwald/flow-react-components"; export default () => { const area: React.CSSProperties = { display: "flex", alignItems: "center", justifyContent: "center", padding: "var(--size-px--xs)", backgroundColor: "var(--info-soft-background-color--default)", border: "1px dashed var(--info-soft-content-color)", borderRadius: "var(--corner-radius--s)", }; const vertical: React.CSSProperties = { writingMode: "vertical-rl", transform: "rotate(180deg)", }; const layout: React.CSSProperties = { alignSelf: "stretch", height: "280px", display: "grid", gridTemplateAreas: ` 'logo header header header' 'primaryNav secondaryNav breadcrumb breadcrumb' 'primaryNav secondaryNav pageTitle button' 'primaryNav secondaryNav content content' `, gridTemplateColumns: "1fr 2fr 12fr 3fr", gridTemplateRows: "auto auto auto 1fr", gap: "var(--size-px--s)", color: "var(--info-soft-content-color)", fontSize: "var(--font-size-text--s)", }; return (
Header
Breadcrumb
Page Title
Button
Content
); } ``` ## Header Der Header-Bereich befindet sich im oberen Bereich des Layouts und ist auf jeder Seite identisch. Er kann das Logo sowie eine [HeaderNavigation](https://flow.mittwald.de/components/navigation/header-navigation) enthalten. Ein Hauptbestandteil der HeaderNavigation sind primäre Navigationspunkte. Ergänzend gibt es [Buttons](https://flow.mittwald.de/components/actions/button), die Overlays oder [ContextMenus](https://flow.mittwald.de/components/actions/context-menu) öffnen, wie beispielsweise für die Suche, das NotificationCenter oder das ProfilMenu. Im Header-Bereich sollten ausschließlich wichtige Elemente angezeigt werden, die auf allen Seiten sichtbar sein müssen. ## Side-Navigation Die Side-Navigation befindet sich entweder direkt links neben dem Content-Bereich oder fest am linken Bildschirmrand. Sie muss nicht nur aus einer Navigation bestehen, sondern kann auch aus einer Primary und einer Secondary Navigation bestehen. Zum Aufbau einer Side-Navigation kann eine [LayoutCard](https://flow.mittwald.de/components/structure/layout-card) mit der Component [Navigation](https://flow.mittwald.de/components/navigation/navigation) gefüllt werden. ## Content Der Content-Bereich stellt dem User Informationen zur Verfügung, damit er seine Aufgabe erfüllen kann. Der Inhalt variiert von Seite zu Seite, es wird jedoch empfohlen, den Inhalt nach einem wiederkehrenden Muster anzuordnen, das bereits auf anderen Seiten verwendet wurde. Die Navigationsstruktur im Content-Bereich folgt ebenfalls einem klaren Muster. Im Content-Bereich können [Tabs](https://flow.mittwald.de/components/structure/tabs) und [List](https://flow.mittwald.de/components/list/list) verwendet werden, um die Inhalte zu teilen oder in die Tiefe zu navigieren. Bei der Navigation in tiefere Ebenen, z. B. über eine List, bietet eine [Breadcrumb](https://flow.mittwald.de/components/navigation/breadcrumb) eine Orientierungshilfe. Der Content wird von einer [LayoutCard](https://flow.mittwald.de/components/structure/layout-card) umschlossen. Um innerhalb der LayoutCard die richtigen Abstände in vertikaler und horizontaler Richtung sicherzustellen, sollten die Layout-Components [Section](https://flow.mittwald.de/components/structure/section) und [ColumnLayout](https://flow.mittwald.de/components/structure/column-layout) verwendet werden. Ein seitenweiter [Alert](https://flow.mittwald.de/components/status/alert#position-seitenweit) steht ebenfalls in der LayoutCard, vor der ersten Section und nicht oberhalb der LayoutCard. ## Overlay Ein Overlay öffnet sich über der eigentlichen Seite. Größere Overlays wie [Modals](https://flow.mittwald.de/components/overlays/modal) und [OffCanvas](https://flow.mittwald.de/components/overlays/modal) erhalten zusätzlich einen Backdrop, damit sich der User besser auf den angezeigten Inhalt konzentrieren kann. Andere, kleinere Overlays wie [ContextMenu](https://flow.mittwald.de/components/actions/context-menu) oder [Tooltip](https://flow.mittwald.de/components/overlays/tooltip) erhalten keinen Backdrop für die im Hintergrund angezeigte Seite. --- # Spacing Spacing definiert die vertikalen und horizontalen Abstände zwischen Elementen und sorgt so für ein harmonisches Layout. --- # Grundlagen Die Spacings und generell alle Größen in Flow basieren auf 8-Pixel-Schritten. Da jedoch oft kleinere Spacings als 8px benötigt werden, stehen zusätzlich feinere Abstufungen von 4px und 2px zur Verfügung. Standardmäßig folgen alle Components den definierten Spacings. Für ein optimales Spacing – das Einfluss auf das Layout hat – sollten die Components [ColumnLayout](https://flow.mittwald.de/components/structure/column-layout) und [Section](https://flow.mittwald.de/components/structure/section) verwendet werden. --- # Best Practices Um mit dem Spacing ein harmonisches Layout zu erschaffen, achte auf folgende Punkte: - Verwende die Layout-Components [ColumnLayout](https://flow.mittwald.de/components/structure/column-layout) und [Section](https://flow.mittwald.de/components/structure/section), um dadurch das richtige vertikale und horizontale Spacing zu erhalten. - Spacing hilft bei der Gruppierung von Elementen auf Benutzeroberflächen. Je geringer das Spacing zwischen den Elementen ist, desto größer ist das Gefühl der Zusammengehörigkeit. - Optisch kann es sinnvoll sein, das Spacing zwischen größeren Elementen größer und zwischen kleineren Elementen kleiner zu wählen. **✅ Do** Zwischen dem [Avatar](https://flow.mittwald.de/components/content/avatar) und dem Namen und Untertitel ist ein Spacing von 8px definiert, da diese Größe ein gutes Zusammengehörigkeitsgefühl vermittelt. ```tsx import { Avatar, Content, Initials, Text, } from "@mittwald/flow-react-components";
Sven Fuchs
Sven Fuchs Projektentwickler
``` **⛔️ Don't** Wenn das Spacing zu groß ist, fühlt sich der Avatar nicht mehr zum Namen und Untertitel gehörig an. ```tsx import { Avatar, Content, Initials, Text, } from "@mittwald/flow-react-components";
Sven Fuchs
Sven Fuchs Projektentwickler
``` --- # Spacing-Tabelle Alle Spacings in der Tabelle können sowohl vertikal und horizontal verwendet werden. Spacings werden in REM angegeben, wenn sie zwischen Elementen eingesetzt werden, die ebenfalls in REM definiert sind. Dies ist zum Beispiel bei Text der Fall, damit der Abstand beim Skalieren der Schriftgröße konsistent bleibt. Zwischen zwei Elementen muss jedoch nicht zwingend ein Spacing verwendet werden, da nicht immer ein Abstand erforderlich ist. | Size | Pixel | REM | (Vertical) Visual | | ----- | ----- | --------- | -------------------------------------------------------------------------------------------------------- | | `xxs` | 2px | 0,125 rem |
| | `xs` | 4px | 0,25 rem |
| | `s` | 8px | 0,5 rem |
| | `m` | 16px | 1 rem |
| | `l` | 24px | 1,5 rem |
| | `xl` | 32px | 2 rem |
| | `xxl` | 64px | 4 rem |
| --- # Components Flow unterstützt das Verschachteln von Components, um deine UI aufzubauen. Dies ist eine kurze Dokumentation darüber, warum wir uns dafür entschieden haben. --- Die folgenden Codebeispiele werden in der Erklärung referenziert. ``` // Flow ``` vs. ``` // Not Flow ``` --- # Logik Components-Libraries basieren in der Regel darauf, Components zu verschachteln, um größere Components zu bauen. Das ist ein weit verbreitetes und effektives Pattern, das außerdem leicht verständlich ist. Genau deshalb unterstützen wir dieses Modell auch in Flow. Wenn man zum Beispiel ein [CounterBadge](https://flow.mittwald.de/components/status/counter-badge) innerhalb eines [Buttons](https://flow.mittwald.de/components/actions/button) platziert, wird dieses automatisch oben rechts positioniert – so, wie man es erwarten würde. --- # Lesbarkeit Wir haben unsere Frontend-Entwickler gefragt, was am Ende besser lesbar ist: 1. Unterkomponenten über Props zu übergeben, wie das [Icon](https://flow.mittwald.de/components/content/icon) im Beispiel 2. Das Icon als Child in die Component zu legen. Wir haben uns für Variante 2 entschieden, da sie besonders bei mehreren Unterkomponenten besser lesbar ist. --- # Wiederverwendbarkeit Entwickler bauen häufig eigene Components, um sie wiederzuverwenden oder um die Implementierung aufzuteilen. Wenn es zum Beispiel bereits eine `UnreadNotificationsCounter`-Component gibt, die den Zähler aus der API lädt und in einem CounterBadge darstellt, kann diese einfach als Child im Button verwendet werden. ``` ``` --- # Suspense- / ErrorBoundaries Nur mit dem „Components-Ansatz“ ist es möglich, Child-Components in Loading- oder ErrorBoundaries zu kapseln. ``` ``` --- # Aufgeblähtes Props-Interface Wenn Components anfangen, Features anderer Components nativ zu unterstützen, wird ihr Props-Interface schnell aufgebläht. Beim Beispiel `counterBadge={7}` könnte man denken: „Hey, das ist doch nur ein Prop mehr und leicht verständlich!“ Aber was ist, wenn CounterBadge mehr Eigenschaften als nur count unterstützt? Jede unterstützte Eigenschaft müsste dann als `counter[CounterProp]` im Button (und möglicherweise weiteren Parent-Components) vorhanden sein. Aufgeblähte Gesamtbibliothek vs. All-Mighty-Components Wenn Flow für jeden Anwendungsfall spezielle Components anbieten würde, müsste es z. B. einen `IconButton`, einen `CounterBadgeButton` und streng genommen sogar einen `IconCounterBadgeButton` geben. Das würde schnell zu sehr vielen Components führen. Und was wäre, wenn man stattdessen alles direkt im Button unterstützt? Das führt meist zu sehr großen „All-Mighty-Components“ ohne klaren Scope und mit überladener Implementierung. --- # Children in Unterkomponenten Nur mit dem „Components-Ansatz“ ist es möglich, Children auch in Unterkomponenten zu verwenden. ``` ``` --- # Baue deine eigenen Components Wenn du bestimmte Kombinationen von Components häufig in deiner UI verwendest, kannst du dir einfach eigene Components mit genau den Props bauen, die du benötigst. --- # Navigation Eine Navigation ist ein zentraler Baustein jeder Benutzeroberfläche. Sie hilft Usern, Inhalte schnell und intuitiv zu finden. Sie verbindet verschiedene Bereiche miteinander, macht Strukturen verständlich und unterstützt ein konsistentes Nutzungserlebnis. Je nach Struktur und Komplexität einer Anwendung kommen unterschiedliche Components zum Einsatz, die häufig sinnvoll miteinander kombiniert werden. --- # Best Practices - **Komplexität reduzieren:** Gestalte Inhalte und Navigationen klar und verständlich. Eine reduzierte und konsistente Navigation verbessert die Orientierung und erleichtert die Nutzung. - **Orientierung schaffen:** User sollten jederzeit erkennen können, wo sie sich befinden. Aktive Zustände, Breadcrumbs und die TabNavigation unterstützen dabei. - **Suche integrieren:** Eine gut sichtbare Suche und Schnellzugriffe erleichtern besonders in komplexen Anwendungen den schnellen Zugriff auf Inhalte. - **Konsistente Navigation:** Navigationsmuster und Positionierungen sollten innerhalb der gesamten Anwendung konsistent verwendet werden. Wiederkehrende Muster erleichtern das Verständnis und stärken die Orientierung. --- # Navigationsstrukturen Hauptnavigationen ermöglichen den Zugriff auf zentrale Bereiche einer Anwendung. Ergänzende Navigationskomponenten innerhalb des Contents schaffen Orientierung, erleichtern den Wechsel zwischen Ansichten und ermöglichen die Navigation auf tieferer Ebene. ## Hauptnavigation Es gibt zwei grundlegende Navigationsvarianten: HeaderNavigation und SideNavigation. Welche eingesetzt wird, hängt vom Layout und der Komplexität der Anwendung ab. Beachte hierbei die Best Practices der Navigationen. ```tsx import { Avatar, Button, Flex, HeaderNavigation, Heading, IconSearch, Initials, Label, LayoutCard, Link, Navigation, NavigationGroup, IconDashboard, IconMonitoring, IconApp, IconContainer, Text, ColumnLayout, } from "@mittwald/flow-react-components"; Dashboard Projekt Server Organisation Mein Projekt Dashboard Monitoring Apps Container Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque eius quam quas vel voluptas, ullam aliquid fugit. Voluptate harum accusantium rerum ullam modi blanditiis vitae, laborum ea tempore, dolore voluptas. Earum pariatur, similique corrupti id officia perferendis. Labore, similique. Earum, quas in. At dolorem corrupti blanditiis nulla deserunt laborum! Corrupti delectus aspernatur nihil nulla obcaecati ipsam porro sequi rem? Quam. ``` ### HeaderNaviagtion Die [HeaderNavigation](https://flow.mittwald.de/components/navigation/header-navigation), befindet sich im oberen Bereich der Seite und eignet sich besonders für Hauptnavigationen mit flacher Struktur und übersichtlicher Informationsarchitektur. Zusätzlich zu den zentralen Navigationspunkten kann sie mit übergeordneten Funktionen ergänzt werden, wie beispielsweise der Zugang zu einem Profil, eine globale Suche oder globale Einstellungen. ### Navigation (SideNavigation) Die [Navigation](https://flow.mittwald.de/components/navigation/navigation) ist vertikal angeordnet und eignet sich besonders für Seitenlayouts mit viel Platz in der Breite oder für Anwendungen mit komplexeren Strukturen. Sie bietet ausreichend Platz für viele Menüpunkte sowie verschachtelte Navigations-Ebenen. Im mStudio wird die SideNavigation aufgrund der komplexen Informationsarchitektur sowohl für Hauptnavigationspunkte als auch für untergeordnete Navigationspunkte genutzt und in einer [LayoudCard](https://flow.mittwald.de/components/structure/layout-card) dargestellt. --- ## Content-Navigation Die Components Breadcrumb, TabNavigation und List unterstützen bei der Orientierung innerhalb des Contents und ermöglichen einen schnellen Wechsel zwischen zusammengehörenden Bereichen oder das Navigieren in tiefere Ebenen. ```tsx import { Flex, Breadcrumb, Link, Heading, LayoutCard, TabNavigation, Section, Text, } from "@mittwald/flow-react-components"; Projekt E-Mails E-Mail-Adresse mail@meinprojekt.de E-Mail-Adressen Postausgänge Archivierung
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque eius quam quas vel voluptas, ullam aliquid fugit. Voluptate harum accusantium rerum ullam modi blanditiis vitae, laborum ea tempore, dolore voluptas. Earum pariatur, similique corrupti id officia perferendis. Labore, similique. Earum, quas in. At dolorem corrupti blanditiis nulla deserunt laborum! Corrupti delectus aspernatur nihil nulla obcaecati ipsam porro sequi rem? Quam.
``` ### Breadcrumb Die [Breadcrumb](https://flow.mittwald.de/components/navigation/breadcrumb) zeigt den aktuellen Pfad innerhalb einer hierarchischen Struktur an. Sie unterstützt die Orientierung, indem sie den Usern jederzeit verdeutlicht, wo sie sich befinden. Zusätzlich erleichtert sie die Rücknavigation zu übergeordneten Ebenen und verbessert damit die Navigierbarkeit komplexerer Anwendungen. ### TabNavigation Die [TabNavigation](https://flow.mittwald.de/components/navigation/tab-navigation) ermöglicht das Navigieren zwischen gleichrangigen Unterseiten. Durch ihre permanente Sichtbarkeit behalten User den Überblick über die verfügbaren Bereiche und erkennen am aktiven Zustand, wo sie sich gerade befinden. Reicht die verfügbare Breite nicht aus, klappen überzählige Punkte automatisch in ein [ContextMenu](https://flow.mittwald.de/components/actions/context-menu) zusammen. ### Listen, Raster und Tabellen Die verschiedenen Darstellungen einer [List](https://flow.mittwald.de/components/list/list) strukturieren Inhalte, schaffen Übersicht über ähnliche Elemente und ermöglichen die Navigation zu detaillierteren Ansichten. --- ## Ergänzende Navigation Klassische Navigationen können durch Verlinkungen, eine globale Suche oder automatische Weiterleitungen ergänzt werden. Gerade in komplexen Anwendungen möchten User schnell zu bestimmten Inhalten gelangen, ohne sich durch die gesamte Navigationsstruktur bewegen zu müssen. Ergänzende Navigationskomponenten ersetzen die Hauptnavigation nicht, sondern erweitern sie gezielt. ### Links [Links](https://flow.mittwald.de/components/navigation/link) ermöglichen den direkten Wechsel in einen anderen Bereich der Anwendung oder zu externen Inhalten. User können dabei selbst entscheiden, ob sie dem Wechsel folgen wollen. Daher sollten Links klar und aussagekräftig benannt sein, damit erkennbar ist, welches Ziel sie haben. ### Suche Die [Suche](https://flow.mittwald.de/components/form-controls/search-field) ermöglicht den direkten Zugriff auf Inhalte, Funktionen oder Bereiche, ohne mehrere Navigationsebenen durchlaufen zu müssen. Besonders in komplexen Anwendungen mit vielen Inhalten unterstützt sie User dabei, Informationen effizient und zielgerichtet zu finden. ### Weiterleitungen Weiterleitungen führen User automatisch oder systemgesteuert zu einer anderen Ansicht oder einem anderen Bereich der Anwendung. Sie sollten bewusst und nachvollziehbar eingesetzt werden, da unerwartete Wechsel schnell zu Orientierungsverlust führen können. --- # Accessibility Eine barrierefreie Navigation stellt sicher, dass alle User die Anwendung zuverlässig bedienen können. - **Semantische Struktur und ARIA-Rollen:** Verwende semantisch korrekte HTML-Elemente und ergänze diese bei Bedarf durch passende ARIA-Rollen und -Attribute. Dadurch können Screenreader Navigationsbereiche korrekt interpretieren und vermitteln. - **Fokus-Reihenfolge und Tastaturbedienung:** Navigations-Elemente müssen vollständig per Tastatur erreichbar und bedienbar sein. Die Fokus-Reihenfolge sollte logisch aufgebaut sein und der visuellen Struktur folgen. - **Verständliche Bezeichnungen:** Navigationspunkte sollten eindeutig benannt sein und verständlich kommunizieren, wohin sie führen. Dadurch wird die Orientierung zusätzlich verbessert. --- # Sprach-Guide Dieser Guide beschreibt, wie wir bei mittwald schreiben. Er gilt für alle Texte im mStudio. Für Extensions ist er eine Hilfe, damit die Texte zu unserem Produkt passen. Du findest hier Leitlinien für deine Texte und einen Glossar mit den Begriffen, die bei mittwald eine eigene Bedeutung haben. --- # Wie wir sprechen ## Technisch und verständlich Wir überzeugen mit Inhalten, nicht mit langen und verschachtelten Erklärungen. Kurze Sätze und einfacher Satzbau halten unsere Texte übersichtlich. Wir drücken uns technisch, aber verständlich aus, genau mit der technischen Tiefe, die dem Nutzer weiterhilft. ## Konsistent Für Aktionen wie Bestellen und Kündigen oder Anlegen und Löschen legen wir feste Begriffspaare fest. Verwende dafür die Begriffe aus unseren [Leitlinien](#leitlinien) und dem [Glossar](#glossar). So erleben unsere Nutzer überall dieselbe Sprache. --- # Leitlinien ## Aktive Sprache Wir agieren aktiv. Das zeigen wir auch in unserer Sprache. Passiv ist in Ordnung, wenn ein System handelt oder der Handelnde keine Rolle spielt, z. B. bei automatischen Vorgängen: „Nach 7 Tagen wird dein Server gelöscht.“ **✅ Do** Du hast den Server gelöscht. **⛔️ Don't** Der Server wurde von dir gelöscht. ## Sie, Du oder Ihr Wir sprechen Nutzer mit „Du“ an und im Singular. In Mailings und Tickets schreiben wir „Du“, „Dein“ und „Deiner“ groß. Im mStudio schreiben wir „du“, „dein“ und „deiner“ klein, weil die Texte eher Anleitungscharakter haben. **✅ Do** Du hast dein Projekt angelegt. **⛔️ Don't** Ihr habt euer Projekt angelegt. ## Kurze Sätze Fass dich kurz. Um Technisches einfach zu formulieren, helfen kurze Sätze. Faustregel: Satzlänge maximal 1,5 Zeilen. 1 Subjekt pro Satz. ## Klare Gliederung Dein Text sollte durch Absätze gegliedert sein. Im besten Fall sind diese nicht länger als 5 Zeilen. Auch Nummerierungen oder Bulletpoints helfen den Lesern, deinem Text besser zu folgen und Wichtiges schneller wahrzunehmen. ## Wichtige Aspekte hervorheben Fette zentrale Begriffe, um Wichtiges in den Vordergrund zu stellen. Beschränke dich dabei auf einzelne Wörter. Ganze Sätze (oder gar Absätze) werden nicht gefettet. ## KEIN! GRUND! ZU! SCHREIEN!!! Wir schreiben ohne Versalien und ohne Ausrufezeichen. Ausnahmen sind etablierte Abkürzungen wie „DSGVO“ und „PHP“ sowie Eigennamen, die selbst ein Ausrufezeichen enthalten, z. B. „Joomla!“. ## Bindestrich: Wörter koppeln Zweisprachige Wortkombinationen werden mit einem Bindestrich gekoppelt. Englische Begriffe werden nicht gekoppelt, deutsche Kombinationen werden zusammengeschrieben. **✅ Do** Ein Tarif-Upgrade kommt selten allein. Erst recht im Cloud Hosting. **⛔️ Don't** Ein Tarif Upgrade allein macht noch keinen Sommer. Auch nicht im Cloud-Hosting. Akronyme werden mit einem Bindestrich gekoppelt, z. B. „DSGVO-konform“. Egal ob mittwald Hosting oder mStudio Login: Die Regel ist immer dieselbe. mittwald und Produktnamen werden niemals mit einem Bindestrich an ein anderes Wort gekoppelt. Generell gilt: Im Zweifel für die Lesbarkeit. Macht die korrekte Schreibweise Probleme (sieht schlecht aus, Umbruch, usw.), missachten wir die Regeln. Das sollte aber nur die Ausnahme sein. ## mittwald, mStudio und vServer werden IMMER kleingeschrieben ... auch am Satzanfang. ## Gendern mittwald lebt Gleichberechtigung. Um kurz und prägnant formulieren zu können, gendern wir jedoch nur dort, wo es Sinn macht, z. B. in Stellenanzeigen. An Orten mit wenig Platz, etwa im mStudio oder auf Social Media, verwenden wir die meist verwendete Schreibweise. ## Zahlen Um die Lesbarkeit zu steigern, schreiben wir alle Zahlen als Ziffern, auch von 0 bis 12. Im UX-Writing gibt es davon eine Ausnahme: Ist die Zahl für den Nutzer nicht besonders relevant und gibt keine konkrete Information wieder, kann sie ausgeschrieben werden. **✅ Do** Nur noch ein Schritt bis zum Abschluss. **⛔️ Don't** Nur noch 1 Schritt bis zum Abschluss. Ist die Zahl dagegen eine wichtige Information, bleibt sie eine Ziffer, z. B. „Nach 7 Tagen wird dein Server gelöscht.“ ## Speicherplatzangaben in binären Einheiten Wir geben Speichergrößen bewusst in binären Einheiten wie KiB, MiB oder GiB an. Diese folgen dem binären System, z. B. 1 GiB = 1.073.741.824 Bytes = 1024³ Bytes. Dadurch stellen wir technische Genauigkeit sicher und vermeiden Verwirrung durch uneinheitliche Umrechnungen, wie sie bei dezimalen Angaben (z. B. KB, MB, GB) häufig auftreten. ## Preise und Umsatzsteuer Wir geben Preise immer mit dem Hinweis „zzgl. USt.“ an. Die Abkürzung „USt.“ verwenden wir nur dort. Im Text schreiben wir „Umsatzsteuer“, nicht „Mehrwertsteuer“. ## Abkürzungen Wir schreiben „inkl.“ in der deutschen Schreibweise und mit Punkt. ## Englischsprachige Inhalte Deutsch bildet die Grundlage unserer Kommunikation. Für englische Texte verwenden wir amerikanisches Englisch (US English). Das betrifft insbesondere Rechtschreibung, Fachbegriffe und UI-Texte. US English entspricht in der Tech-Welt dem etablierten Standard. **✅ Do** color, behavior, organization **⛔️ Don't** colour, behaviour, organisation ## Nutzer, nicht Kunde Im Produkt sprechen wir von „Nutzern“. Den Begriff „Kunde“ verwenden wir nicht. Wer mit uns einen Vertrag hat, ist ein „Vertragspartner“ (siehe Glossar). ## Technische Fachbegriffe Etablierte technische Fachbegriffe übersetzen wir nicht, sondern lassen sie englisch, z. B. „SSH-User“. „Nutzer“ gilt für Personen, die das Produkt nutzen. Bezeichnet „User“ dagegen ein technisches Konto, bleibt es „User“. **✅ Do** Lege einen Cronjob an. **⛔️ Don't** Lege eine zeitgesteuerte Aufgabe an. ## AI und KI Im Kontext von AI Hosting schreiben wir „AI“. Sonst kann „KI“ im Fließtext verwendet werden. ## Gegenstücke für Aktionen Wir nennen die Aktion und ihr Gegenstück konsistent: Wer etwas **installiert**, kann es **deinstallieren**. Wer ein Verb für den Anfang einer Aktion wählt, nimmt für ihre Umkehrung das passende Gegenstück. Für die häufigsten Verben legen wir die Paare fest: | Aktion | Gegenstück | Wann | | ------------ | -------------- | ----------------------------------------------------------- | | Anlegen | Löschen | Ein Objekt wird von Grund auf erstellt, die Daten sind weg. | | Hinzufügen | Entfernen | Ein bestehendes Objekt wird zugeordnet oder wieder gelöst. | | Bestellen | Kündigen | Eine kostenpflichtige Bestellung wird beendet. | | Installieren | Deinstallieren | Gilt nur für Software, z. B. Apps und Systemsoftware. | | Einladen | Ausladen | Gilt für Personen, die Zugriff erhalten. | Alle anderen Verben folgen demselben Prinzip, ohne dass sie hier stehen. --- # Glossar Dieser Glossar erklärt Begriffe, die im Produkt eine eigene Bedeutung haben und ohne Definition missverstanden werden könnten. Regeln zur Wortwahl stehen in den Leitlinien. - **Artikel:** Alle kostenpflichtigen Produkte, z. B. Domains, die hinzubestellt werden. - **Organisation:** Der Vertrags- und Abrechnungsrahmen. Hier werden Zahlungsinformationen und Vertragspartnerdaten hinterlegt. - **Projekt:** Bündelt alles, was für den Betrieb einer Website oder Webanwendung nötig ist, z. B. Apps, Domains, Datenbanken und E-Mail-Postfächer. - **Ressourcen:** Die Rechenleistung und der Speicherplatz, die ein Server oder Projekt zur Verfügung hat: vCPU, RAM und Speicherplatz. - **Server:** Stellt Ressourcen bereit, die sich mehrere Projekte teilen. - **Umsatzsteuer:** Die Steuer auf unsere Preise. Wir sagen „Umsatzsteuer“, nicht „Mehrwertsteuer“. - **Vertragspartner:** Eine natürliche oder juristische Person, die mit uns einen Vertrag abgeschlossen hat. Das ist nicht zwangsläufig ein Nutzer. --- # Informationskonzept Das Informationskonzept beschreibt, wie der User im mStudio über alle relevanten Informationen informiert wird – sowohl durch selbst initiierte Aktionen als auch durch systemseitig ausgelöste Ereignisse. Dazu zählen laufende und abgeschlossene Prozesse sowie wichtige Systemmeldungen (z. B. „Speicherplatz ist voll“). Es definiert, wie Feedback zu Prozessen gegeben wird und wie Benachrichtigungen gestaltet sind. --- # Status Das Informationskonzept unterscheidet verschiedene Status. Jeder Status folgt dabei einem definierten Kombination aus [Color](https://flow.mittwald.de/foundations/design/colors)- und [Icon](https://flow.mittwald.de/components/content/icon#icon-bibliothek), um eine eindeutige und schnelle Erkennung zu ermöglichen. Wenn zwei Status inhaltlich miteinander konkurrieren, wird immer der handlungsentscheidende angezeigt. Zum Beispiel überschreibt ein Danger stets Warning und Info. | Status | Einsatz | Beispiel | | --------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | Info | Sachliche Hinweise/Informationen ohne akuten Handlungsbedarf | - Update verfügbar
- Download wird vorbereitet
- Kündigung vorgemerkt
- Neue Nachricht im Ticket
- Aktive Anlegeprozesse | | Warning | Handlungsempfehlung oder Hinweis möglicher Konflikt | - Speicherplatz fast voll
- E-Mail Versand gesperrt
- Domain unverifiziert
- Zertifikat konnte nicht ausgestellt werden | | Danger | Kritisches Problem, das sofortiges Handeln erfordert | - Speicherplatz voll
- E-Mail Empfang deaktiviert
- Webserver/Cronjobs deaktiviert | | Success | Erfolgreich abgeschlossene Ereignisse | - Erfolgreich installiert
- Erfolgreich angelegt
- Erfolgreich erstellt
- Domain verifiziert | | Unavailable | Nicht verfügbare Elemente | - Fehlende Berechtigungen
- Gelöschtes Objekt | --- # Alert Ein [Alert](https://flow.mittwald.de/components/status/alert) wird dort eingesetzt, wo unmittelbare Aufmerksamkeit erforderlich ist – etwa bei Systemfehlern oder wichtigen Systeminformationen. Er übermittelt die Information in wenigen Sätzen und gibt, wenn möglich, eine Handlungsempfehlung. Diese kann mithilfe eines [Links](https://flow.mittwald.de/components/navigation/link) oder eines [Buttons](https://flow.mittwald.de/components/actions/button) unterstützt werden. Alerts sollten stets in der Nähe des betroffenen Inhalts platziert werden (s. [Alert: Position](https://flow.mittwald.de/components/status/alert#position)). Ein seitenweiter Alert steht in der [LayoutCard](https://flow.mittwald.de/components/structure/layout-card#kombiniere-mit-alert) vor der ersten Section und nicht oberhalb der LayoutCard. ```tsx import { Alert, Heading, Text, Content, Button, Link, } from "@mittwald/flow-react-components"; <> E-Mail-Adresse wurde archiviert Da deine Domain gelöscht wurde, wurde diese E-Mail-Adresse archiviert. Um E-Mails empfangen und senden zu können musst du die Adresse wieder umbenennen. Dein Speicher ist fast voll Dein Speicher ist zu über 80% belegt. Wir empfehlen dir deinen Speicherplatz zu erweitern, um Problemen vorzubeugen. Es konnte kein SSL-Zertifikat ausgestellt werden Für diese Domain konnte kein SSL-Zertifikat ausgestellt werden, da die Domain per IP nicht auf deine Server-IP zeigt. App aktualisiert Deine App wurde erfolgreich auf die neueste Version aktualisiert. Mehr Informationen zur aktuellen Version Inhalte nicht gefunden Die gewünschten Inhalte sind leider nicht verfügbar. Entweder wurden sie inzwischen gelöscht oder dir fehlen die notwendigen Berechtigungen. ``` --- # AlertBadge Eine [AlertBadge](https://flow.mittwald.de/components/status/alert-badge) dient dazu, den Status eines Elements schnell sichtbar zu machen, beispielsweise in [Headings](https://flow.mittwald.de/components/content/heading) oder [List](https://flow.mittwald.de/components/list/list)-Einträgen. In vielen Fällen wird sie durch einen [Alert](https://flow.mittwald.de/components/status/alert) ergänzt, etwa auf der [Detailseite](https://flow.mittwald.de/templates/seiten/detailseite), um zusätzliche Informationen bereitzustellen. Für Metadaten oder ergänzende Informationen ist hingegen die [Badge](https://flow.mittwald.de/components/status/badge) besser geeignet (siehe [AlertBadge vs. Badge](https://flow.mittwald.de/components/status/alert-badge#best-practices-alertbadge-vs-badge)). ```tsx import { AlertBadge } from "@mittwald/flow-react-components"; <> Update verfügbar Speicherplatz fast voll Speicherplatz voll Verifiziert Nicht gefunden ``` --- # Notifications [Notifications](https://flow.mittwald.de/components/status/notification) informieren über wichtige System- oder Statusmeldungen und erscheinen kurz im Bildschirm des Users. So stellen sie sicher, dass User über einen Status informiert werden, auch wenn sie sich gerade nicht auf der betroffenen [Detailseite](https://flow.mittwald.de/templates/seiten/detailseite) befinden. Notifications sollten bewusst und sparsam eingesetzt werden. Denn zu viele Notifications überfluten den User und lenken von wirklich wichtigen Informationen ab. Notifications werden durch den [NotificationsProvider](https://flow.mittwald.de/components/status/notification-provider) ausgelöst. Da Notifications in der Regel nur kurz sichtbar sind, sollten sie an einem zentralen Ort gesammelt werden, damit ungelesene Notifications auch zu einem späteren Zeitpunkt eingesehen werden können. Kritische Probleme sollten zusätzlich zur Notification per E-Mail kommuniziert werden. So wird sichergestellt, dass der User die Informationen zuverlässig erhält. ```tsx import { Heading, Notification, Text, } from "@mittwald/flow-react-components"; <> E-Mail-Adresse archiviert Die E-Mail-Adresse example@mittwald.de wurde archiviert. Speicher fast voll Der Speicherplatz im Projekt My Project ist zu 80% voll. Kein SSL-Zertifikat Für exmaple.de konnte kein SSL-Zertifikat ausgestellt werden. App installiert Deine App My WordPress wurde erfolgreich installiert. Nicht gefunden Die gewünschten Inhalte sind leider nicht verfügbar. ``` --- # Status-Icon Einzelne [Status-Icons](https://flow.mittwald.de/components/content/icon#icon-bibliothek) können den User auf versteckte Status-Informtionen aufmerksam machen. Zum Beispiel zeigt ein Status-Icon innerhalb von einem [Tab](https://flow.mittwald.de/components/structure/tabs) an, dass in diesem ein relevanter Status vorliegt. Der Status kann dann im Tab z. B. mit Hilfe eines [Alerts](https://flow.mittwald.de/components/status/alert) erläutert werden. ```tsx import { Tabs, Tab, TabTitle, AlertIcon, } from "@mittwald/flow-react-components"; Tab Tab Content Tab Tab Content Tab Tab Content ``` --- # Fehlermeldungen Der beste Fehler ist der, der gar nicht erst auftritt. Klare Strukturen, verständliche Beschriftungen und sinnvolle Defaults helfen, Fehlbedienungen zu vermeiden. Lassen sich Fehler nicht verhindern, entscheiden zwei Dinge darüber, ob Nutzer weiterkommen: wo und mit welcher Komponente der Fehler erscheint und wie er formuliert ist. --- # Best Practices - Vermeide Fehler schon im Design, zum Beispiel durch klare Beschriftungen und sinnvolle Defaults. - Zeige Fehler dort, wo sie entstehen oder wo der erwartete Inhalt wäre. - Nenne eine Lösung oder biete einen Ausweg an, zum Beispiel "Erneut laden". - Wähle die Darstellung passend zum Umfang des Fehlers. - Bleibe sachlich: keine Schuldzuweisungen und keine Entschuldigungen. - Formuliere kurz und positiv. Das hilft Nutzern, schnell zu handeln. --- # Fehlermeldungen anzeigen ## Beim Laden von Inhalten Beim Laden können Fehler auftreten, zum Beispiel wenn ein Service nicht erreichbar ist oder ein Timeout entsteht. Beende in diesem Fall den Ladezustand, damit Nutzer sehen, dass sie nicht weiter warten müssen. Die Fehlermeldung erscheint dort, wo der erwartete Inhalt wäre. Für größere Bereiche wie [LayoutCards](https://flow.mittwald.de/components/structure/layout-card) oder [Sections](https://flow.mittwald.de/components/structure/section) eignet sich eine [IllustratedMessage](https://flow.mittwald.de/components/content/illustrated-message) mit `status="danger"`. Sie zeigt deutlich, dass der Inhalt aktuell nicht verfügbar ist, und bietet idealerweise eine Handlung an, zum Beispiel einen [Button](https://flow.mittwald.de/components/actions/button) mit der Beschriftung "Erneut laden". ```tsx import { Flex, Heading, IconDanger, IllustratedMessage, LayoutCard, Text, } from "@mittwald/flow-react-components"; export default () => { return ( Mein Projekt Fehler beim Laden von Daten Dieser Bereich konnte nicht geladen werden. Wir arbeiten daran das Problem zu beheben. Bitte habe etwas Geduld und probiere es später noch einmal. ); } ``` Für kleinere, abgegrenzte Elemente wie Tabellen- oder Listenzeilen eignet sich ein [AlertText](https://flow.mittwald.de/components/status/alert-text). So bleibt der Kontext erhalten und der Fehler betrifft nicht die ganze [Table](https://flow.mittwald.de/components/structure/table) oder [List](https://flow.mittwald.de/components/list/list). ```tsx import { AlertText, Avatar, Content, Flex, Heading, IconDomain, LayoutCard, ListItemView, Text, typedList, } from "@mittwald/flow-react-components"; export default () => { const DomainList = typedList<{ id: string; domain: string; target?: string; }>(); return ( Domains domain.id} loadingItemsCount={3} > domain.domain} > {(domain) => ( {domain.domain} {domain.target ? ( domain.target ) : ( Fehler beim Laden )} )} ); } ``` Um Fehler auf kleine Bereiche zu begrenzen, nutzen wir im mStudio Loading und Error Boundaries. Sie kapseln technische Fehler ab und sorgen für konsistentes Feedback. ## Bei ungültigen Eingaben Zeige das Feedback direkt am Form Control, damit Nutzer sofort erkennen, was sie anpassen müssen. Details stehen unter [Formular (Mit Validierung)](https://flow.mittwald.de/templates/bausteine/formular#varianten-und-abwandlung-mit-validierung). ## Bei fehlgeschlagenen Aktionen Aktionen, die einen Request an das Backend senden, können aus technischen Gründen, wegen Kommunikationsproblemen oder fehlender Berechtigungen fehlschlagen. Dafür eignet sich ein [Modal](https://flow.mittwald.de/components/overlays/modal) mit einer [IllustratedMessage](https://flow.mittwald.de/components/content/illustrated-message) mit `status="danger"`. Sie erklärt kurz den Grund, sofern er für Nutzer relevant ist, und bietet einen Ausweg an, zum Beispiel die Aktion erneut auszuführen. ```tsx import { Action, ActionGroup, Button, Content, Flex, Heading, IconDanger, IconProject, IllustratedMessage, LayoutCard, Modal, Text, useModalController, } from "@mittwald/flow-react-components"; export default () => { const controller = useModalController(); return ( Projekte Erstes Projekt anlegen Du hast noch keine Projekte angelegt! Lege ein Projekt an und schon kannst du mit dem Entwickeln loslegen. { controller.open(); }} > Fehler beim Ausführen der Aktion Die Aktion konnte nicht ausgeführt werden. Wir arbeiten daran das Problem zu beheben. Bitte habe etwas Geduld und probiere es später noch einmal. ); } ``` Schlägt eine Aktion erst später fehl, nachdem sie zunächst erfolgreich an das Backend übermittelt wurde, eignen sich [Notifications](https://flow.mittwald.de/components/status/notification) besser. Ein typisches Beispiel ist das Registrieren einer Domain. Mehr dazu steht im [Informationskonzept](https://flow.mittwald.de/foundations/content-guidelines/informationskonzept). --- # Fehlermeldungen formulieren Die allgemeinen Regeln zu Anrede und Satzlänge stehen im [Sprach-Guide](https://flow.mittwald.de/foundations/content-guidelines/sprach-guide). Dort steht auch, dass eine passive Schreibweise in Ordnung ist, wenn ein System handelt. Das trifft bei Fehlermeldungen oft zu. Für sie gilt zusätzlich: ## Kurz formulieren und Lösung nennen Schreibe so kurz wie möglich, aber so lang wie nötig. Oft reicht es, nur die Lösung zu nennen. Gibt es mehrere mögliche Ursachen, beschreibe, wie sich die wahrscheinlichste beheben lässt. **✅ Do** **⛔️ Don't** Wir unterstützen die Formatierung nicht. Gib eine E-Mail-Adresse im Format name@domain.de ein. ## Schuldzuweisungen vermeiden Beschreibe, was passiert ist, und nicht, was der Nutzer falsch gemacht hat. Ein Fehler ist an sich schon frustrierend. **✅ Do** Das Bild konnte nicht hochgeladen werden. Wähle eine Datei bis 10 MB. **⛔️ Don't** Du hast ein ungültiges Bild hochgeladen. Wähle eine Datei bis 10 MB. ## Nicht entschuldigen Formuliere Fehlermeldungen sachlich und fachlich. Entschuldigungen lenken vom Wesentlichen ab und lassen Fehler größer wirken. **✅ Do** Die Eingabe konnte nicht gespeichert werden. Versuche es erneut. **⛔️ Don't** Es tut uns leid, wir konnten deine Eingabe nicht speichern. Versuche es erneut. ## Positiv formulieren Konzentriere dich auf die Lösung und darauf, was als Nächstes möglich ist. Verzichte nach Möglichkeit auf negativ besetzte Begriffe wie Fehler, Problem, fehlgeschlagen, falsch oder ungültig. Bei Systemfehlern ohne direkte Lösung gelingt das nicht immer. **⛔️ Don't** Durch ein Problem mit dem Server ist die Verbindung fehlgeschlagen. ## Allgemein formulieren Formuliere eher allgemein als zu spezifisch. Details wie Dateinamen oder Ordner finden Nutzer meist an anderer Stelle in der Oberfläche. **✅ Do** Die Datei konnte nicht hochgeladen werden. Verwende eine Datei vom Typ XY. **⛔️ Don't** Die Datei „example_file-20.4.24.xy“ konnte nicht hochgeladen werden. Verwende eine Datei vom Typ XY. --- # Focus Task **focus-task.tsx** ```tsx import { Button, Flex, Heading, Label, LayoutCard, Link, Section, Text, TextField, } from "@mittwald/flow-react-components"; import styles from "./focus-task.module.css"; export default () => (
Login Passwort vergessen Du hast noch keinen Nutzer?{" "} Registrieren
Datenschutz Impressum
) ``` **focus-task.module.css** ```css .page { /* Container-relative here; use 100dvh in a real full-page app. */ height: 100%; background: var(--texture--grain), var(--color--background-gradient); background-blend-mode: overlay, normal; } .center { width: 100%; max-width: 30rem; } /* * The wordmark rides on `currentColor` through a CSS mask, so it follows the * theme (dark on light, light on dark). Swap the masked SVG for your own logo. */ .logo { align-self: center; width: 18rem; max-width: 100%; aspect-ratio: 300 / 57; background: currentcolor; mask: url("./mittwald.svg") no-repeat center / contain; -webkit-mask: url("./mittwald.svg") no-repeat center / contain; } .registerLine { text-align: end; } /* The generous page padding is too much for a narrow screen. */ @media (max-width: 768px) { .page { padding-inline: var(--size-px--m); } } ``` --- # Verwendung Ein Focus Task ist eine einzelne Seite ohne umgebende Navigation. Verwende ihn für einen klar abgegrenzten Vorgang wie Registrierung, Anmeldung, Konfiguration oder Bestellung. Ohne Navigation bleibt der Nutzer auf die eine Aufgabe konzentriert und schließt sie zielgerichtet ab. --- # Aufbau - **Content** – Die Aufgabe liegt in einer [LayoutCard](https://flow.mittwald.de/components/structure/layout-card): Eingaben und Aktionen stehen direkt darin, ohne umgebende Navigation. - **Footer** – Hier lassen sich [Links](https://flow.mittwald.de/components/navigation/link) platzieren, etwa Verweise auf Datenschutz oder Impressum. --- # Varianten und Abwandlung ## Konfigurations-Aufgabe Auch eine mehrteilige Aufgabe bleibt ein Focus Task, solange sie ohne Navigation auf ein Ziel führt. Über die [ActionGroup](https://flow.mittwald.de/components/actions/action-group) gelangt der Nutzer zum jeweils nächsten Schritt. **focus-task-bestellung.tsx** ```tsx import { Badge, Button, ColumnLayout, Content, Flex, Heading, Label, LayoutCard, Link, RadioButton, RadioGroup, Section, Table, TableBody, TableCell, TableColumn, TableFooterRow, TableHeader, TableRow, Text, TextField, } from "@mittwald/flow-react-components"; import styles from "./focus-task-bestellung.module.css"; export default () => ( Bestellung
Individuell konfigurieren Passe deinen Tarif ganz einfach an deine Bedürfnisse an. Wähle Ressourcen und Speicherplatz so, wie du sie wirklich brauchst, und stelle dir deinen passenden Tarif zusammen. Ressourcen Die Ressourcen aus vCPU und RAM bestimmen die Leistung deines Tarifs. Du kannst sie jederzeit nach der Buchung anpassen. 1 vCPU 1 GiB RAM 1 vCPU Empfehlung 2 GiB RAM 2 vCPU 4 GiB RAM Speicherplatz Der Speicherplatz umfasst Datenbanken, Backups, Webspace und E-Mails aller Projekte auf deinem Tarif. 20 GiB 40 GiB 60 GiB 80 GiB 100 GiB Individuell
Kostenübersicht Artikel Monatliche Kosten 1 vCPU / 2 GiB RAM 17,00 € 40 GiB Speicher 2,00 € Aktionsrabatt -5,00 € Gesamt 14,00 €
Datenschutz Impressum
) ``` **focus-task-bestellung.module.css** ```css .page { /* Container-relative here; use 100dvh in a real full-page app. */ min-height: 100%; background: var(--texture--grain), var(--color--background-gradient); background-blend-mode: overlay, normal; } .center { width: 100%; max-width: 84rem; } /* * The wordmark rides on `currentColor` through a CSS mask, so it follows the * theme. Swap the masked SVG for your own logo. */ .logo { align-self: flex-start; width: 12rem; max-width: 100%; aspect-ratio: 300 / 57; background: currentcolor; mask: url("./mittwald.svg") no-repeat center / contain; -webkit-mask: url("./mittwald.svg") no-repeat center / contain; } /* * The RadioButton lays its slots out on a grid ("icon label" / ". content"). * A raw child lands in the wrong cell, so the title row claims the label area. */ .resourceTitle { grid-area: label; } .actionsRight { margin-inline-start: auto; } /* The generous page padding is too much for a narrow screen. */ @media (max-width: 768px) { .page { padding-inline: var(--size-px--m); } } ``` --- # Simple App **simple-app.tsx** ```tsx import { ActionGroup, Avatar, Button, CartesianChart, ChartGrid, ChartLegend, ChartTooltip, ColumnLayout, Combine, Content, ContextMenu, ContextMenuTrigger, CounterBadge, DonutChart, Flex, Header, HeaderNavigation, Heading, Icon, IconLogout, IconMenu, IconNotification, IconSettings, Initials, LayoutCard, Line, Link, MenuItem, Message, MessageThread, Modal, ModalTrigger, Navigation, Rating, Section, Text, XAxis, YAxis, } from "@mittwald/flow-react-components"; import { IconTrendingDown, IconTrendingUp, } from "@tabler/icons-react"; import styles from "./simple-app.module.css"; const contracts = [ { month: "Jan", Webhosting: 33, vServer: 72, "Dedicated Server": 52, }, { month: "Feb", Webhosting: 52, vServer: 84, "Dedicated Server": 80, }, { month: "Mär", Webhosting: 62, vServer: 83, "Dedicated Server": 98, }, { month: "Apr", Webhosting: 24, vServer: 63, "Dedicated Server": 42, }, { month: "Mai", Webhosting: 70, vServer: 78, "Dedicated Server": 50, }, { month: "Jun", Webhosting: 96, vServer: 88, "Dedicated Server": 54, }, { month: "Jul", Webhosting: 146, vServer: 98, "Dedicated Server": 56, }, { month: "Aug", Webhosting: 132, vServer: 85, "Dedicated Server": 90, }, { month: "Sep", Webhosting: 114, vServer: 82, "Dedicated Server": 148, }, { month: "Okt", Webhosting: 18, vServer: 42, "Dedicated Server": 120, }, { month: "Nov", Webhosting: 48, vServer: 70, "Dedicated Server": 98, }, { month: "Dez", Webhosting: 68, vServer: 110, "Dedicated Server": 126, }, ]; export default () => (
Profil Abmelden
{/* The active area is already named in the navigation, so the page heading is only exposed to assistive technology. */} Dashboard
Neuverträge
+ 2.000 € Vertragsbestand (30 Tage) 40 Neuverträge (30 Tage)
Vertragszusammensetzung 1,2 K
Letzte Kundenfeedbacks
Datenschutz Impressum
); /* * The bell keeps its place next to the burger: a pending notification is worth * seeing without opening the menu first. */ const NotificationButton = () => ( ); /* * The navigation links, shared by the top bar and the off-canvas. Each renders * them through its own props context, so the same Links read as a header bar * in one and as a navigation list in the other. */ const GlobalNavigationLinks = () => ( <> Dashboard Kündigungen Vertragsbestand ); /* * On a narrow screen the top bar has no room for the navigation, so it moves * in here. The burger is then the shell's only navigation control. */ const MobileMenu = () => ( Menü ); interface FeedbackProps { name: string; date: string; rating: number; text: string; } const Feedback = ({ name, date, rating, text, }: FeedbackProps) => (
{name} {name} {date}
{text}
) ``` **simple-app.module.css** ```css .app { /* Header and content share one maximum width, so their edges line up. */ --page-width: 1800px; /* The header's tint is mixed from the gradient's first stop. */ --header-ground: var(--neutral--color--200); /* Container-relative here; use 100dvh in a real full-page app. */ min-height: 100%; background: var(--texture--grain), var(--color--background-gradient); background-blend-mode: overlay, normal; } /* * The header stays at the top while the page scrolls beneath it. Its tint is * translucent and blurred, so the navigation stays legible above the content. */ .header { position: sticky; top: 0; z-index: 1; padding-block: var(--size-px--m); background-color: color-mix(in srgb, var(--header-ground) 40%, transparent); backdrop-filter: blur(var(--blur)); } .headerContent { max-width: var(--page-width); margin-inline: auto; padding-inline: var(--size-px--xl); } .content { width: 100%; max-width: var(--page-width); margin-inline: auto; padding-block: var(--size-px--s) var(--size-px--l); padding-inline: var(--size-px--xl); } /* * The wordmark rides on `currentColor` through a CSS mask, so it follows the * theme. Swap the masked SVG for your own logo. */ .logo { width: 9rem; max-width: 100%; aspect-ratio: 300 / 57; background: currentcolor; mask: url("./mittwald.svg") no-repeat center / contain; -webkit-mask: url("./mittwald.svg") no-repeat center / contain; } /* The navigation is pushed to the far end of the top bar. */ .nav { margin-inline-start: auto; } /* The bell and the burger take that place once the navigation gives it up. */ .mobileActions { margin-inline-start: auto; } /* Keeps the heading in the accessibility tree while hiding it visually. */ .visuallyHidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } /* A single metric: trend icon, the value, and its caption. */ .stat { text-align: center; } .statValue { font-size: 1.75rem; font-weight: var(--font-weight--bold, 700); } .statLabel { font-weight: var(--font-weight--medium); } .footer { margin-block-start: auto; } /* * Below this width the top bar has no room for the navigation, so it hands its * links to the off-canvas behind the burger. */ @media (max-width: 768px) { .nav { display: none; } .headerContent, .content { padding-inline: var(--size-px--m); } } @media (min-width: 769px) { .mobileActions { display: none; } } @media (prefers-contrast: more), (prefers-reduced-transparency) { .header { background-color: var(--header-ground); backdrop-filter: none; } } /* The dark gradient starts darker than the neutral token. */ [data-theme="dark"] .app { --header-ground: #121518; } ``` --- # Verwendung Eine Simple App führt wenige gleichrangige Bereiche unter einer einzigen, flachen Navigationsebene zusammen. Verwende sie für ein überschaubares Werkzeug, dessen Bereiche alle auf einer Ebene liegen. Die flache Struktur macht jeden Bereich mit einem Klick erreichbar. Sobald eine zweite Navigationsebene nötig wird, ist es eine [Complex App](https://flow.mittwald.de/templates/app-shells/complex-app). --- # Aufbau - **Header** – Eine [HeaderNavigation](https://flow.mittwald.de/components/navigation/header-navigation) bildet die einzige, flache Navigationsebene über die gleichrangigen Bereiche und bietet Raum für bereichsübergreifende Funktionen wie eine Suche oder die Profilverwaltung. Er bleibt beim Scrollen oben stehen, der Inhalt läuft darunter durch. - **Content** – Der Inhalt ist auf eine maximale Breite begrenzt und wird in der Regel in [LayoutCards](https://flow.mittwald.de/components/structure/layout-card) dargestellt. Typische Seitentypen sind beispielsweise [Detailseiten](https://flow.mittwald.de/templates/seiten/detailseite), [Dashboards](https://flow.mittwald.de/templates/seiten/dashboard) und [Übersichtsseiten](https://flow.mittwald.de/templates/seiten/uebersichtsseite). - **Footer** – Hier lassen sich [Links](https://flow.mittwald.de/components/navigation/link) platzieren, etwa Verweise auf Datenschutz oder Impressum. Auf schmalen Screens ist für die Header-Navigation kein Platz. Sie gibt ihre Links an ein [OffCanvas](https://flow.mittwald.de/components/overlays/modal) ab, das ein Burger-Menü in der Kopfleiste öffnet. --- # Varianten und Abwandlung ## Mit seitlicher Navigation Wenn der Header nicht genug Platz für alle gleichrangigen Bereiche bietet, wandert die flache Navigation nach links in eine [Navigation](https://flow.mittwald.de/components/navigation/navigation). Sie nimmt auch das Logo, globale Funktionen wie Benachrichtigungen und Einstellungen sowie das Nutzerprofil auf, sodass der Header ganz entfällt. Die Struktur bleibt einstufig und damit eine Simple App. Öffnet ein Wechsel je Bereich eine eigene Seitennavigation, entsteht eine [Complex App](https://flow.mittwald.de/templates/app-shells/complex-app). **simple-app-sidebar.tsx** ```tsx import { Avatar, Badge, Button, ColumnLayout, Combine, CounterBadge, Flex, Heading, IconCustomer, IconDashboard, IconInvoice, IconLogout, IconNotification, IconPayment, IconQuote, IconSettings, Initials, LayoutCard, Link, Navigation, Section, Text, typedList, } from "@mittwald/flow-react-components"; import styles from "./simple-app-sidebar.module.css"; type Status = "Bezahlt" | "Offen" | "Überfällig"; const statusColor: Record< Status, "green" | "neutral" | "red" > = { Bezahlt: "green", Offen: "neutral", Überfällig: "red", }; interface Invoice { number: string; customer: string; createdAt: string; // ISO date, sorted on date: string; // formatted for display amount: string; status: Status; } // A page of invoices, one per day counting back from 30.09.2026, with enough // rows to sort, filter and search through. const invoices: Invoice[] = [ { number: "RE-2026-0148", customer: "KD-1298", createdAt: "2026-09-30", date: "30.09.2026", amount: "844,00 €", status: "Offen", }, { number: "RE-2026-0149", customer: "KD-0553", createdAt: "2026-09-29", date: "29.09.2026", amount: "965,00 €", status: "Bezahlt", }, { number: "RE-2026-0150", customer: "KD-0987", createdAt: "2026-09-28", date: "28.09.2026", amount: "917,00 €", status: "Bezahlt", }, { number: "RE-2026-0151", customer: "KD-0553", createdAt: "2026-09-27", date: "27.09.2026", amount: "844,00 €", status: "Überfällig", }, { number: "RE-2026-0152", customer: "KD-1298", createdAt: "2026-09-26", date: "26.09.2026", amount: "418,00 €", status: "Überfällig", }, { number: "RE-2026-0153", customer: "KD-0553", createdAt: "2026-09-25", date: "25.09.2026", amount: "1.434,00 €", status: "Offen", }, { number: "RE-2026-0154", customer: "KD-0553", createdAt: "2026-09-24", date: "24.09.2026", amount: "1.559,00 €", status: "Offen", }, { number: "RE-2026-0155", customer: "KD-0765", createdAt: "2026-09-23", date: "23.09.2026", amount: "2.032,00 €", status: "Überfällig", }, { number: "RE-2026-0156", customer: "KD-0987", createdAt: "2026-09-22", date: "22.09.2026", amount: "2.269,00 €", status: "Bezahlt", }, { number: "RE-2026-0157", customer: "KD-1298", createdAt: "2026-09-21", date: "21.09.2026", amount: "1.230,00 €", status: "Offen", }, { number: "RE-2026-0158", customer: "KD-1042", createdAt: "2026-09-20", date: "20.09.2026", amount: "2.771,00 €", status: "Offen", }, { number: "RE-2026-0159", customer: "KD-0987", createdAt: "2026-09-19", date: "19.09.2026", amount: "2.556,00 €", status: "Offen", }, { number: "RE-2026-0160", customer: "KD-1298", createdAt: "2026-09-18", date: "18.09.2026", amount: "669,00 €", status: "Bezahlt", }, { number: "RE-2026-0161", customer: "KD-1042", createdAt: "2026-09-17", date: "17.09.2026", amount: "1.761,00 €", status: "Bezahlt", }, { number: "RE-2026-0162", customer: "KD-0553", createdAt: "2026-09-16", date: "16.09.2026", amount: "871,00 €", status: "Überfällig", }, ]; export default () => { const InvoiceList = typedList(); return (
{/* The current user sits at the very bottom of the sidebar. */} Max Mustermann Max Mustermann {/* The active area is already named in the navigation, so the page heading is only exposed to assistive technology. */} Rechnungen
invoice.number} > Rechnungsnummer Kundennummer Ausstellungsdatum Betrag Status {(invoice) => invoice.number} {(invoice) => invoice.customer} {(invoice) => invoice.date} {(invoice) => invoice.amount} {(invoice) => ( {invoice.status} )}
Datenschutz Impressum
); }; /* * The flat list of equal-ranking areas — the single navigation level of a * Simple App, moved from the header into the sidebar. */ const AreaNavigation = () => ( Dashboard Rechnungen Angebote Kunden Zahlungseingang ); /* * Supplementary points that would be out of place among the areas. They sit * apart from the flat list above. */ const AdminNavigation = () => ( Benachrichtigungen Einstellungen ) ``` **simple-app-sidebar.module.css** ```css /* The container the page-scroll switch below is measured against. */ .shell { container-type: inline-size; height: 100%; background: var(--texture--grain), var(--color--background-gradient); background-blend-mode: overlay, normal; } .app { /* Fixed to the viewport height (container-relative here; use 100dvh in a real full-page app) so the cards below can fill it and scroll their own content instead of growing the page. */ height: 100%; max-width: 1800px; margin-inline: auto; overflow: hidden; } /* * The wordmark rides on `currentColor` through a CSS mask, so it follows the * theme. Swap the masked SVG for your own logo. */ .logo { width: 9rem; max-width: 100%; aspect-ratio: 300 / 57; /* Extra breathing room between the wordmark and the navigation below it. */ margin-block-end: var(--size-px--m); background: currentcolor; mask: url("./mittwald.svg") no-repeat left center / contain; -webkit-mask: url("./mittwald.svg") no-repeat left center / contain; } /* Sidebar and content fill the available height side by side; the column layout stacks them once its container gets narrow. */ .body { flex: 1; min-height: 0; } /* The column layout's inner grid fills that height, so its row stretches. */ .body > * { height: 100%; } /* The navigation card scrolls its own content if the viewport is too short for it. */ .sidebar { align-self: stretch; gap: var(--size-px--m); min-height: 0; overflow: auto; } /* Settings and the user profile sit at the bottom, apart from the areas above. */ .sidebarBottom { margin-block-start: auto; } .main { align-self: stretch; min-width: 0; min-height: 0; } /* The content card grows with its content, but only up to the viewport: once it would run past the bottom it stops there and scrolls its own overflow (the long invoice list) instead of growing the page. */ .contentCard { flex: 0 1 auto; min-height: 0; overflow: auto; } /* Keeps the heading in the accessibility tree while hiding it visually. */ .visuallyHidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } .footer { margin-block-start: auto; } /* * Once the column layout stacks the cards (its content box at or below 850px, * i.e. 850px plus the xl side padding), the page scrolls as a whole rather than * each card scrolling on its own inside a fixed height. */ @container (max-width: 914px) { .app { height: auto; overflow: visible; } .sidebar { overflow: visible; } .main { min-height: auto; } .contentCard { flex: none; min-height: auto; overflow: visible; } } @media (max-width: 768px) { .app { padding-inline: var(--size-px--m); } } ``` --- # Complex App **complex-app.tsx** ```tsx import { ActionGroup, Avatar, Breadcrumb, Button, Content, ContextMenu, ContextMenuTrigger, CounterBadge, Flex, HeaderNavigation, Heading, IconApp, IconCronjob, IconDashboard, IconDatabase, IconDomain, IconEmail, IconLogout, IconMember, IconMenu, IconMonitoring, IconNotification, IconSearch, IconSettings, IconSshSftp, Initials, Label, LayoutCard, Link, MenuItem, Modal, ModalTrigger, Navigation, NavigationGroup, ProgressBar, Section, Text, typedList, } from "@mittwald/flow-react-components"; import styles from "./complex-app.module.css"; interface Mailbox { id: string; address: string; type: string; color: "blue" | "teal" | "violet"; storage?: { used: number; max: number }; } const mailboxes: Mailbox[] = [ { id: "1", address: "max.mustermann@mittwald.de", type: "E-Mail-Adresse", color: "blue", storage: { used: 1, max: 2 }, }, { id: "2", address: "kontakt@mittwald.de", type: "E-Mail-Adresse", color: "blue", storage: { used: 0.5, max: 2 }, }, { id: "3", address: "info@mittwald.de", type: "Weiterleitungsadresse", color: "teal", }, { id: "4", address: "hallo@mittwald.de", type: "Catch-All-Adresse", color: "violet", storage: { used: 0, max: 2 }, }, ]; const MailboxList = typedList(); export default () => ( Projekt E-Mails E-Mails m.id} > m.address} > {(m) => ( {m.address} {m.type} {m.storage && ( )} Details anzeigen Bearbeiten Löschen )}