# Microsoft Fluent 2 Designsystem

## Microsoft Fluent 2 Interface-Vorschau des Designsystems

Wechseln Sie zwischen „Brief“ und „Personen“, schalten Sie das Web-Theme um und testen Sie ungültige, doppelte und erfolgreiche lokale Einträge. Es wird keine Einladung versendet.

## Microsoft Fluent 2 Designsystem – Designreferenz

Referenzen für Fluent UI React v9 im Web. Globale numerische Werte stammen aus den verknüpften React-Tokenquellen. Die unten aufgeführten Farbwerte lösen die Alias-Zuordnung für den hellen Modus mit brandWeb auf und verwenden nicht die veralteten beispielhaften Hex-Kommentare in alias/lightColor.ts. Für dunkle Farben und Teams-Themes gelten separate Zuordnungen. In der Typografietabelle der Website ist Subtitle1 derzeit mit 20/26 angegeben; die Quelle React fonts.ts verwendet 20/28, woran sich diese Implementierung orientiert. Quellen geprüft am 3. Oktober 2026; gleiche die Angaben mit der in deiner Lockdatei erfassten Version ab.

### Neutrale Rollen im hellen Theme

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| colorNeutralForeground1 | #242424 | Primärer Dokumenttext. |
| colorNeutralForeground2 | #424242 | Sekundäre Beschriftungen. |
| colorNeutralForeground3 | #616161 | Metadaten; den endgültigen Kontrast trotzdem prüfen. |
| colorNeutralBackground1 | #ffffff | Hauptfläche. |
| colorNeutralBackground2 | #fafafa | Zurückhaltende unterstützende Fläche. |
| colorNeutralBackground3 | #f5f5f5 | Arbeitsbereichsfläche. |
| colorNeutralStroke1 | #d1d1d1 | Übliche Komponentenumrandung. |
| colorNeutralStroke2 | #e0e0e0 | Dezente Trennlinie. |
| colorNeutralStrokeAccessible | #616161 | Kontrastreichere Umrandung für Steuerelemente. |
| colorNeutralForegroundOnBrand | #ffffff | Text auf unterstützenden Markenfarbflächen. |
| colorStrokeFocus1 / colorStrokeFocus2 | #ffffff / #000000 | Zwei Fokusfarben; den Kontrast am Komponentenumrand erhalten. |
### Web-Markenrollen, aufgelöst aus brandWeb

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| colorBrandBackground | #0f6cbd · brandWeb[80] | Primäre Aktion in webLightTheme. |
| colorBrandBackgroundHover | #115ea3 · brandWeb[70] | Hover-Variante dieser Aktion. |
| colorBrandBackgroundPressed | #0c3b5e · brandWeb[40] | Gedrückte Variante; kein allgemeiner Status für ausgewählte Elemente. |
| colorBrandBackground2 | #ebf3fc · brandWeb[160] | Dezenter Markenfarbhintergrund. |
| colorBrandForegroundLink | #115ea3 · brandWeb[70] | Link-Vordergrundfarbe im hellen Web-Theme. |
### Horizontaler und vertikaler Abstand

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| spacingHorizontalNone / spacingVerticalNone | 0 | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalXXS / spacingVerticalXXS | 2px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalXS / spacingVerticalXS | 4px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalSNudge / spacingVerticalSNudge | 6px | Achse entsprechend der Layoutrichtung wählen; kleiner Korrekturwert für die Symbolausrichtung. |
| spacingHorizontalS / spacingVerticalS | 8px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalMNudge / spacingVerticalMNudge | 10px | Achse entsprechend der Layoutrichtung wählen; kleiner Korrekturwert für die Symbolausrichtung. |
| spacingHorizontalM / spacingVerticalM | 12px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalL / spacingVerticalL | 16px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalXL / spacingVerticalXL | 20px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalXXL / spacingVerticalXXL | 24px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
| spacingHorizontalXXXL / spacingVerticalXXXL | 32px | Achse entsprechend der Layoutrichtung wählen; gemeinsamer Abstandsschritt. |
### React Web-Typografiekombinationen

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| Caption2 · fontSizeBase100 | 10px / 14px / 400 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase100 kombinieren. |
| Caption1 · fontSizeBase200 | 12px / 16px / 400 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase200 kombinieren. |
| Body1 · fontSizeBase300 | 14px / 20px / 400 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase300 kombinieren. |
| Body2 / Subtitle2 · fontSizeBase400 | 16px / 22px / 400 / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase400 kombinieren. |
| Subtitle1 · fontSizeBase500 | 20px / 28px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase500 kombinieren. |
| Title3 · fontSizeBase600 | 24px / 32px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightBase600 kombinieren. |
| Title2 · fontSizeHero700 | 28px / 36px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightHero700 kombinieren. |
| Title1 · fontSizeHero800 | 32px / 40px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightHero800 kombinieren. |
| LargeTitle · fontSizeHero900 | 40px / 52px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightHero900 kombinieren. |
| Display · fontSizeHero1000 | 68px / 92px / 600 | Größe / Zeilenhöhe / Schriftstärke. Mit lineHeightHero1000 kombinieren. |
### Schriftfamilie und Schriftstärke

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| fontFamilyBase | 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif | Standardmäßiger Web-Schriftstapel des Anbieters; die umgebende Website-Schrift nicht als Fluent bezeichnen. |
| fontFamilyMonospace | Consolas, 'Courier New', Courier, monospace | Code und technische Bezeichner. |
| fontWeightRegular / Medium / Semibold / Bold | 400 / 500 / 600 / 700 | Die Schriftstärke der Rolle mit der dazugehörigen Typografieskala verwenden. |
### Form-Tokens

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| borderRadiusNone | 0 | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadiusSmall | 2px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadiusMedium | 4px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadiusLarge | 6px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadiusXLarge | 8px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadius2XLarge | 12px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadius3XLarge | 16px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadius4XLarge | 24px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadius5XLarge | 32px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadius6XLarge | 40px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
| borderRadiusCircular | 10000px | Zuerst den Komponentenstandard verwenden; dies ist ein verfügbarer Token, keine Vorgabe für jede Fläche. |
### Abstufung der Animationsdauer

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| durationUltraFast | 50ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationFaster | 100ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationFast | 150ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationNormal | 200ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationGentle | 250ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationSlow | 300ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationSlower | 400ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
| durationUltraSlow | 500ms | Verfügbarer Laufzeit-Token; das Beispiel verwendet Fast für Hover und deaktiviert Übergänge bei reduzierter Bewegung. |
### Theme-Änderungen sind semantisch, keine Umkehrung

| Name / Regel | Wert / Konfiguration | Verwendung |
| --- | --- | --- |
| colorNeutralBackground1 | #292929 | Dunkle Hauptfläche statt hellem #ffffff. |
| colorNeutralForeground1 | #ffffff | Dunkler primärer Text statt hellem #242424. |
| colorNeutralForeground2 | #d6d6d6 | Dunkler sekundärer Text. |
| colorBrandBackground | brandWeb[70] = #115ea3 | Dunkle primäre Füllfarbe; im hellen Modus wird brandWeb[80] verwendet. |
| colorBrandForegroundLink | brandWeb[100] = #479ef5 | Dunkle Linkrolle; unterscheidet sich von der Füllfarbe der primären Schaltfläche. |
## Microsoft Fluent 2 Designsystem: vollständiger Leitfaden

Ein praktischer Leitfaden zur Auswahl, Anwendung und Überprüfung dieses Systems für ein echtes Interface.

Umfassende Anleitung, Einstieg in die Implementierung und Links zu den Quellen.

## Microsoft Fluent 2 Designsystem und die Implementierung mit React v9

### Die Web-Implementierung ausdrücklich auswählen

> Fluent 2 ist eine plattformübergreifende Designsprache. Dieser Leitfaden trifft eine engere, direkt nutzbare Wahl: @fluentui/react-components, die konsolidierte React-v9-Bibliothek. Als Stammkomponente dient FluentProvider; in diesem Beispiel kommt webLightTheme oder webDarkTheme zum Einsatz. Ein Teams-Theme ist eine separate Marken-Konfiguration; das vertraute Lila in Teams ist nicht die standardmäßige blaue Web-Farbskala. Auch native Ressourcen für Windows, iOS und Android sind nicht mit React-Paketen austauschbar.

Das vollständige Beispiel unten rendert eine Projektbeschreibung und eine lokale Zugriffsliste. Es kombiniert Title3 und Body1 für die Hierarchie, TabList und Tab für zwei Ansichten sowie Dialog mit Field, Input und Select für eine Zugriffsentscheidung. Der Code gibt nicht vor, eine echte Person einzuladen. So lässt sich das Verhalten der Komponenten veranschaulichen, ohne einen Freigabedienst zu erfinden.

Unterstützende Spezifikation lesen

### Was FluentProvider tatsächlich bereitstellt

FluentProvider stellt Theme-Variablen in seinem Unterbaum bereit. Eine benutzerdefinierte Fläche mit tokens.colorNeutralBackground2 folgt dem ausgewählten Theme, eine fest auf Weiß gesetzte Fläche dagegen nicht. Platziere den Provider oberhalb der Komponenten, die das Theme benötigen. Die Bibliothek gestaltet ihre Komponenten über ihre Styling-Laufzeit; das Beispiel setzt keinen erfundenen Import einer Datei namens fluent.css voraus.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem: semantische Farben und die echte Web-Markenfarbskala

### Aliase anhand der ausgewählten Marke auflösen

Die Alias-Quelle für den hellen Modus weist colorBrandBackground dem Wert brand[80] zu. Das Web-Theme stellt brandWeb bereit, wobei Stufe 80 dem Wert #0f6cbd entspricht. In diesem Beispiel ist #0f6cbd daher die aufgelöste primäre Füllfarbe. Die Alias-Datei enthält ältere Hex-Kommentare zur Veranschaulichung. Wer diese Kommentare als aktuelle Web-Farbpalette interpretiert, erhält ein falsches Ergebnis. Maßgeblich ist die Zuordnung in der Quelle, nicht der Kommentar.

Verwende colorNeutralForeground1 für die Projektbeschreibung, colorNeutralForeground2 für ergänzende Beschriftungen und colorNeutralBackground3 für den umgebenden Arbeitsbereich. Für eine primäre Aktion eignen sich colorBrandBackground und colorNeutralForegroundOnBrand. Bei einem Theme-Wechsel bleiben die Rollennamen maßgeblich. Die Berechtigung einer Person wird durch Text dargestellt; ein blauer Rand oder eine blaue Markierung auf einem Tab zeigt eine Auswahl an, keine Zugriffsberechtigung.

Unterstützende Spezifikation lesen

### Der Dark Mode ändert die Zuordnung

Im Dark Mode werden die Hauptfläche zu #292929 und der primäre Text zu #ffffff aufgelöst. Die primäre Markenfüllfarbe verwendet Stufe 70, während die Link-Vordergrundfarbe Stufe 100 verwendet. Deshalb ändert die Vorschau die zugehörigen Tokenrollen gemeinsam, statt lediglich den Seitenhintergrund umzukehren. Vergleiche nach dem Umschalten den Zugriffsdialog, den ausgewählten Tab und die gedämpften Metadaten: Sie alle gehören zur gleichen Theme-Grenze.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem-Typografie: Textrollen Laufzeit-Tokens zuordnen

### Zugehörige Werte für Schriftgröße und Zeilenhöhe verwenden

Body1 ist der grundlegende Lesestil mit 14px Schriftgröße und 20px Zeilenhöhe. Caption1 verwendet 12/16, Subtitle2 16/22 mit halbfetter Schriftstärke und Title3 24/32 mit halbfetter Schriftstärke. Diese Wertepaarungen schaffen eine klare Hierarchie zwischen Titel, Beschriftung und Fließtext, ohne willkürliche Zwischengrößen. Die Tabelle oben enthält zur Orientierung auch größere Stufen; ein kompakter Arbeitsbereich braucht jedoch keine überschrift in Display-Größe.

Die React-Tokenquelle und die Design-Website weichen derzeit bei einem hilfreichen Detail voneinander ab: fontSizeBase500 / lineHeightBase500 beträgt in der Laufzeitquelle 20/28, während die Web-Typografietabelle Subtitle1 mit 20/26 angibt. Dieses Beispiel folgt dem Wertepaar aus der Laufzeitquelle. Behandle solche Abweichungen als Anlass, Version und Implementierung zu prüfen, statt stillschweigend jeweils die Werte zu kombinieren, die zum Mock-up passen.

Unterstützende Spezifikation lesen

### Textvorgaben und Schriftstapel

HTML semantisch neben dem visuellen Preset verwenden: Title3 as="h1" ist eine Überschrift; allein die Gestaltung erzeugt keine Dokumentstruktur. Der Basisschriftartenstapel beginnt mit Segoe UI und enthält Fallbacks für verschiedene Plattformen. Binde keine proprietäre Schriftart ein, nur damit ein Screenshot identisch aussieht. Das Beispiel verwendet den dokumentierten Schriftartenstapel; die genauen Glyphen hängen daher von den auf dem Anzeigegerät installierten Schriftarten ab.

Für benutzerdefinierte Texte bündelt typographyStyles.body1 Schriftfamilie, Größe, Stärke und Zeilenhöhe. Bevorzuge diese Kombination, statt nur fontSizeBase300 zu kopieren. In der Zugriffsliste werden gut lesbare E-Mail-Adressen mit Zeilenumbruch angezeigt; die Berechtigungsbezeichnung ist halbfett hervorgehoben, ohne mit dem Seitentitel zu konkurrieren.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem: Abstände, Form und Dichte in einem Arbeitsbereich

### Die Abstandsbezeichnungen von React entsprechen nicht den Namen im Design-Tool

Die allgemeinen Fluent-Layout-Richtlinien verwenden globale Größenbezeichnungen und einen Vierer-Rhythmus, einschließlich 2, 6 und 10 für Ausrichtungsanpassungen. React stellt achsenspezifische Aliase bereit: spacingHorizontalS entspricht 8px, M 12px, L 16px und XXL 24px; dazu gibt es passende vertikale Bezeichnungen. Übersetze size120 nicht in spacingHorizontal120; diese Kennung von React existiert nicht.

Diese Komposition verwendet 24px Innenabstand im Bedienfeld, 16px Abstand zwischen Formularfeldern und 12px Abstand zwischen Zugriffszeilen. Die genaue Seitenbreite und die zweispaltige Anordnung sind Entscheidungen der Anwendung, keine offiziellen Fluent-Haltepunkte. Auf schmalen Bildschirmen wird der ergänzende Teamkontext unter der Kurzbeschreibung angezeigt, während die beiden Registerbeschriftungen sichtbar bleiben.

Unterstützende Spezifikation lesen

### Die Form richtet sich nach der Komponentengröße

Zu den verfügbaren Radius-Token gehören Medium mit 4px und XLarge mit 8px. Ihre Verfügbarkeit bedeutet jedoch nicht, dass jedes Steuerelement denselben Radius erhält. Das HTML-Beispiel verwendet als bewusste Gestaltungsentscheidungen eine Steuerelementform mit 4px und eine Dokumentoberfläche mit 8px. Native Komponenten sollten ihre jeweils unterstützte Standardanatomie beibehalten, sofern die gewählte Designanforderung keine Überschreibung rechtfertigt. Greife nicht auf generierte Klassennamen zurück, um eine andere Form zu erzwingen.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem TabList: Auswahl, Panels und Tastaturverhalten

### Der ausgewählte Wert gehört zum Anwendungsstatus

Das Beispiel verwaltet den Tab in React als Status und übergibt ihn an selectedValue. onTabSelect erhält data.value, wodurch dieser Status aktualisiert wird. Jeder Tab hat einen stabilen Wert und verweist über aria-controls auf sein Panel. Jedes Panel hat role="tabpanel", aria-labelledby und eine hidden-Bedingung. Die Komponente stellt weder die Projektkurzbeschreibung noch die Zugriffsliste bereit; diese werden explizit gerendert.

API trennt Fokussieren und Auswählen: selectTabOnFocus ist standardmäßig false. Im eigenständigen Beispiel bewegen Links-/Rechtspfeil und Pos1/Ende den Fokus; Enter oder die Leertaste aktiviert den fokussierten Tab. Dieses Verhalten mit manueller Aktivierung ermöglicht es, die Tab-Auswahl zu prüfen, ohne unerwartet den Inhalt zu wechseln. Halte die Tab-Beschriftungen kurz; laut den offiziellen Layout-Richtlinien werden horizontale Tabs nicht automatisch umgebrochen oder scrollbar.

Unterstützende Spezifikation lesen

### Bei mehr Kategorien ein anderes Muster wählen

Kurzbeschreibung und Personen sind zwei eng verwandte Ansichten eines Arbeitsbereichs, daher eignen sich Tabs. Eine Liste aller Projekte der Organisation wäre Navigation und keine weitere Tab-Reihe. Wenn die Kategorien bei schmaler Ansicht nicht mehr hineinpassen, gestalte bewusst einen Überlaufmechanismus oder ein anderes Auswahlmuster. Beschriftungen so weit zu verkleinern, bis sie unleserlich sind, ist keine Strategie für responsives Design.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem Field: barrierefreie Beschriftungen und aussagekräftige Validierung

### Ein Field ist eine Komposition, kein gestaltetes Eingabefeld

Field kombiniert einen Beschriftungs-Slot, das darin enthaltene Steuerelement, einen optionalen Hinweis und eine Validierungsmeldung. Der dokumentierte Vertrag für Steuerelemente umfasst id, aria-labelledby, aria-describedby, aria-invalid und aria-required. Fluent-Eingabefelder können direkte untergeordnete Elemente sein; benutzerdefinierte Steuerelemente können die Props der Render-Funktion entgegennehmen. Deshalb ist es hilfreicher, das E-Mail-Input in Field einzubetten, als beliebigen Text über einem Eingabefeld zu platzieren.

Im Beispiel ist validationState erst nach einer ungültigen lokalen Übermittlung auf error gesetzt. Die Anwendung prüft, ob der Wert dem Format einer E-Mail-Adresse entspricht und ob er in der In-Memory-Liste bereits vorkommt. Der eingegebene Wert bleibt erhalten, und validationMessage enthält einen Korrekturhinweis. Field zeigt das Ergebnis an und ordnet es dem Eingabefeld zu; die Komponente prüft weder, ob die Adresse existiert, noch versendet sie eine Einladung oder gewährt Zugriff.

Unterstützende Spezifikation lesen

### Validierungsstatus und Berechtigung getrennt halten

Das Berechtigungs-Select enthält Can view und Can edit, während das E-Mail-Feld einen eigenen Fehlerstatus hat. Vermeide es, einen gesamten Dialog rot darzustellen, nur weil eine Adresse unvollständig ist. required ist ein barrierefreier Hinweis und kein Ersatz für die serverseitige Autorisierung oder Validierung. Das Beispielformular verwendet noValidate, damit die explizite Validierungsmeldung konsistent demonstriert werden kann; ein Produktivdienst muss die Anfrage erneut validieren.

- Leere oder fehlerhafte Adresse: Dialog geöffnet lassen und das zulässige Format erklären.

- Adresse bereits in der lokalen Zugriffsliste: eine spezifische Meldung zu Duplikaten anzeigen, ohne eine weitere Zeile hinzuzufügen.

- Neue gültige Adresse: die ausgewählte Berechtigung lokal hinzufügen, den Dialog schließen und transparent auf das nur lokal ausgeführte Ergebnis hinweisen.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2 Designsystem Dialog: ein Formular innerhalb der unterstützten Anatomie

### Die Schaltfläche zum Absenden im Formular belassen

Die Komposition besteht aus Dialog, DialogTrigger, DialogSurface, einem form-Element und DialogBody mit DialogTitle, DialogContent und DialogActions. Das Formular umschließt den Body, damit die Submit-Schaltfläche im Footer Teil des Formulars ist. Cancel hat type="button" und befindet sich in einem schließenden DialogTrigger. Andernfalls könnte der Standardtyp der Schaltfläche das Formular versehentlich absenden.

open und onOpenChange steuern die Sichtbarkeit. disableButtonEnhancement verhindert, dass der Trigger eine Fluent Button, die bereits Schaltflächenverhalten bereitstellt, redundant erweitert. Der Erfolgs-Handler schließt den Dialog erst nach erfolgreicher lokaler Validierung. Bei einem Validierungsfehler bleiben dieselbe E-Mail-Adresse und Berechtigung zur Korrektur erhalten.

Unterstützende Spezifikation lesen

### Das modale Verhalten an der tatsächlichen Entscheidung ausrichten

Diese kurze Zugriffsentscheidung verwendet den Standarddialogtyp. Ein nicht modaler Dialog würde Arbeiten im Hintergrund ermöglichen, während ein Alarmdialog für eine dringende Entscheidung vorgesehen ist und strengere Regeln zum Schließen hat. Ein gewöhnliches Zugriffsformular benötigt keine Alarmsemantik. Die offizielle Anleitung empfiehlt, den Fokus im Dialog zu platzieren und ihn nach dem Schließen auf den Auslöser zurückzusetzen. Die eigenständige Umsetzung verwendet das native Dialogelement und stellt den Fokus ausdrücklich auf dem Auslöser wieder her.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2-Designsystem: Benutzerdefinierte Gestaltung ohne das Theme zu beeinträchtigen

### makeStyles und semantische Variablen verwenden

Der vollständige Code verwendet makeStyles mit Design Tokens für Oberflächen, Abstände und Eckenradien. So bleibt das benutzerdefinierte Panel auf den Provider abgestimmt. Ein generierter Klassenname ist ein Implementierungsdetail. Übernehmen Sie ihn daher nicht aus den DevTools in ein Stylesheet. Wenn Sie mit Themes experimentieren, ändern Sie das Provider-Theme und prüfen Sie native Steuerelemente und benutzerdefinierte Bereiche gemeinsam.

Die veröffentlichte Dauerabstufung reicht von 50ms bis 500ms. Das HTML-Beispiel verwendet durationFast mit 150ms für einfache Hover-Änderungen und deaktiviert diese Übergänge bei prefers-reduced-motion. Das ist eine Anwendungsentscheidung, bei der ein verfügbarer Token genutzt wird, und keine Aussage, dass jede Fluent-Interaktion 150ms dauern muss. Inhalte und Fehlermeldungen bleiben auch ohne Animation verständlich.

Unterstützende Spezifikation lesen

### Die Grenzen einer Interpretation testen

Das eingebettete Beispiel ist absichtlich als HTML/CSS gekennzeichnet und nicht als native Fluent-Implementierung. Es veranschaulicht die verifizierten Werte und die Interaktion des Zugriffsdialogs, ohne beim Anzeigen ein Framework herunterzuladen. Verwenden Sie das vollständige React-Beispiel, wenn Sie natives Styling, Portale, Fokusverwaltung und Komponentenaktualisierungen bewerten. Wenn die eigenständige Interaktion die Prüfungen besteht, ist das ein Nachweis für dieses Beispiel, aber keine Zertifizierung einer produktiven Freigabeanwendung.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2-Designsystem: Vollständige Komposition installieren und überprüfen

### Ein ausführbarer Einstiegspunkt statt einer Aufgabenübersicht

Das Setup ist für eine bestehende React-Anwendung mit einem Element namens root ausgelegt. Installiere die v9-Suite und füge den JSX-Einstiegspunkt anschließend in die Anwendung ein. Imports, Provider, Komponentenbaum, Handler, Zustand und Root-Rendering sind gemeinsam enthalten. Es wird kein externes Sharing-API aufgerufen. Rendert dein Starter bereits App, behalte dessen Root-Einstiegspunkt bei und exportiere App, statt einen zweiten Root zu erstellen.

Halten Sie die aufgelöste Paketversion in der Lockdatei fest. Die verlinkten Quellen beschreiben die untersuchte Implementierung von React v9; master-URLs können sich ändern. Vergleichen Sie vor einem Upgrade das exportierte Theme sowie das genaue Verhalten von Field, TabList und Dialog, das hier verwendet wird. Bei der Einrichtung werden v8-Komponenten aus @fluentui/react bewusst nicht mit v9-Beispielen kombiniert.

1. Installieren Sie @fluentui/react-components@9 im bestehenden React-Projekt und behalten Sie die generierte Lockdatei bei.

2. Rendern Sie den bereitgestellten Einstiegspunkt unter einem einzigen FluentProvider, mit webLightTheme als initialem Theme.

3. Öffnen Sie den Dialog, senden Sie eine ungültige Adresse ab, korrigieren Sie sie und bestätigen Sie, dass die hinzugefügte Person nur im lokalen Status erscheint.

4. Wiederholen Sie den Test mit webDarkTheme und per Tastaturnavigation. Überprüfen Sie die Verknüpfung des Panels, die Ansage des Fehlers und die Rückgabe des Fokus.

Unterstützende Spezifikation lesen

### Was in einem echten Freigabeprodukt angebunden werden muss

Ersetzen Sie das lokale Hinzufügen erst, wenn der Servicevertrag festgelegt ist: authentifizierter Akteur, Zielarbeitsbereich, zulässige Berechtigungswerte, Ergebnis der Einladung und Verhalten bei Duplikaten. Bleibt eine Anfrage beim Service erfolglos, lassen Sie den Dialog geöffnet und zeigen Sie das bestätigte Ergebnis an, statt den Zugriff voreilig als gewährt darzustellen. Diese Regeln sind nicht Teil von Fluent. Der Code macht jedoch die Übergabestelle ausdrücklich kenntlich, statt sie hinter einer generischen Schaltfläche zum Absenden zu verbergen.

Unterstützende Spezifikation lesen

## Microsoft Fluent 2-Designsystem: Komponentenbeispiele

### Vollständige, eigenständige interaktive Demo

Speichern Sie das vollständige Dokument als index.html und öffnen Sie es in einem Browser. Eigenständige Umsetzung von Fluent UI React v9 Web-Tokens und der dokumentierten Anatomie von Field, TabList und Dialog mit HTML/CSS. Keine native Fluent-Komponentenlaufzeit.

```
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Fluent web workspace study</title><style>
:root{color-scheme:light;--colorNeutralForeground1:#242424;--colorNeutralForeground2:#424242;--colorNeutralForeground3:#616161;--colorNeutralBackground1:#fff;--colorNeutralBackground2:#fafafa;--colorNeutralBackground3:#f5f5f5;--colorNeutralStroke1:#d1d1d1;--colorNeutralStroke2:#e0e0e0;--colorBrandBackground:#0f6cbd;--colorBrandBackgroundHover:#115ea3;--colorBrandBackgroundPressed:#0c3b5e;--colorBrandBackground2:#ebf3fc;--colorBrandForegroundLink:#115ea3;--colorNeutralForegroundOnBrand:#fff;--borderRadiusMedium:4px;--borderRadiusXLarge:8px;--spacingHorizontalS:8px;--spacingHorizontalM:12px;--spacingHorizontalL:16px;--spacingHorizontalXXL:24px;--durationFast:150ms}
[data-theme=dark]{color-scheme:dark;--colorNeutralForeground1:#fff;--colorNeutralForeground2:#d6d6d6;--colorNeutralForeground3:#adadad;--colorNeutralBackground1:#292929;--colorNeutralBackground2:#1f1f1f;--colorNeutralBackground3:#141414;--colorNeutralStroke1:#666;--colorNeutralStroke2:#525252;--colorBrandBackground:#115ea3;--colorBrandBackgroundHover:#0f6cbd;--colorBrandBackground2:#082338;--colorBrandForegroundLink:#479ef5}
*{box-sizing:border-box}body{margin:0;background:var(--colorNeutralBackground3);color:var(--colorNeutralForeground1);font-family:'Segoe UI','Segoe UI Web (West European)',-apple-system,BlinkMacSystemFont,Roboto,'Helvetica Neue',sans-serif;font-size:14px;line-height:20px}button,input,select{font:inherit}button{cursor:pointer;min-height:32px;padding:5px 12px;border:1px solid var(--colorNeutralStroke1);border-radius:var(--borderRadiusMedium);background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);font-weight:600;transition:background var(--durationFast)}button:hover{background:var(--colorNeutralBackground3)}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--colorBrandForegroundLink);outline-offset:3px}.primary{background:var(--colorBrandBackground);color:var(--colorNeutralForegroundOnBrand);border-color:transparent}.primary:hover{background:var(--colorBrandBackgroundHover)}.primary:active{background:var(--colorBrandBackgroundPressed)}.topbar{display:flex;justify-content:space-between;align-items:center;padding:12px 24px;background:var(--colorNeutralBackground1);border-bottom:1px solid var(--colorNeutralStroke2);gap:16px}.brand{display:flex;align-items:center;gap:12px;font-weight:600}.mark{display:grid;grid-template-columns:repeat(2,7px);gap:3px}.mark i{width:7px;height:7px;background:var(--colorBrandBackground)}.top-note{font-size:12px;color:var(--colorNeutralForeground3)}.page{max-width:1100px;margin:auto;padding:24px}.heading{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:16px}.eyebrow{font-size:12px;line-height:16px;color:var(--colorNeutralForeground3);margin-bottom:4px}h1{font-size:24px;line-height:32px;font-weight:600;margin:0 0 4px}h2{font-size:20px;line-height:28px;font-weight:600;margin:0 0 16px}h3{font-size:16px;line-height:22px;font-weight:600;margin:20px 0 8px}p{margin:0 0 12px}.muted{color:var(--colorNeutralForeground3)}.tabs{display:flex;gap:16px;border-bottom:1px solid var(--colorNeutralStroke2);margin-bottom:24px}.tab{position:relative;background:none;border:0;border-radius:0;font-weight:400;padding:12px 4px;color:var(--colorNeutralForeground2)}.tab[aria-selected=true]{font-weight:600;color:var(--colorBrandForegroundLink)}.tab[aria-selected=true]:after{content:'';position:absolute;bottom:0;left:4px;right:4px;height:3px;background:var(--colorBrandBackground);border-radius:3px}.layout{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:24px}.document,.aside,.people{background:var(--colorNeutralBackground1);border:1px solid var(--colorNeutralStroke2);border-radius:var(--borderRadiusXLarge);padding:24px}.document{max-width:720px}.docmeta{display:flex;gap:8px;align-items:center;color:var(--colorNeutralForeground3);font-size:12px;line-height:16px;margin-bottom:24px}.avatar{flex:none;display:grid;place-items:center;background:var(--colorBrandBackground2);color:var(--colorBrandForegroundLink);font-weight:600;width:32px;height:32px;border-radius:50%}.quote{padding:12px 16px;background:var(--colorNeutralBackground2);border-left:3px solid var(--colorBrandBackground);margin:16px 0}.checklist{list-style:none;padding:0;margin:12px 0}.checklist li{display:flex;gap:8px;margin:8px 0}.checklist input{accent-color:var(--colorBrandBackground);width:16px;height:16px;margin-top:2px}.aside{padding:20px;height:fit-content}.aside h2{font-size:16px;line-height:22px;margin-bottom:16px}.person{display:flex;gap:8px;align-items:center;margin-bottom:16px}.person p{margin:0}.small{font-size:12px;line-height:16px}.aside hr{border:0;border-top:1px solid var(--colorNeutralStroke2);margin:20px 0}.tag{display:inline-block;border:1px solid var(--colorNeutralStroke1);padding:2px 8px;border-radius:4px;font-size:12px;color:var(--colorNeutralForeground2)}.people-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;gap:12px}.people-head h2{margin:0}.people ul{list-style:none;padding:0;margin:0}.member{display:flex;align-items:center;gap:12px;padding:16px 0;border-top:1px solid var(--colorNeutralStroke2)}.member-info{flex:1;min-width:0;overflow-wrap:anywhere}.member-info p{margin:0}.member .tag{flex:none}.caption{margin:20px 0 0;color:var(--colorNeutralForeground3);font-size:12px;line-height:16px}.status{margin-top:16px;overflow-wrap:anywhere;color:var(--colorNeutralForeground2)}.status:empty{display:none}[hidden]{display:none!important}dialog{width:min(520px,calc(100vw - 32px));padding:24px;border:1px solid var(--colorNeutralStroke1);border-radius:8px;background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);max-height:calc(100dvh - 32px);overflow:auto}dialog::backdrop{background:rgba(0,0,0,.4)}dialog h2{font-size:20px;line-height:28px;margin-bottom:12px}.field{margin:20px 0}.field label{display:block;font-weight:600;margin-bottom:8px}.required{color:#b10e1e}.field input,.field select{width:100%;min-height:36px;background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);padding:7px 12px;border:1px solid var(--colorNeutralStroke1);border-bottom-color:var(--colorNeutralForeground3);border-radius:4px}.field input:focus{border-bottom:2px solid var(--colorBrandBackground);padding-bottom:6px}.hint{font-size:12px;line-height:16px;color:var(--colorNeutralForeground3);margin-top:8px}.error{font-size:12px;line-height:16px;color:#b10e1e;margin-top:8px}.field input[aria-invalid=true]{border-color:#b10e1e}.actions{display:flex;justify-content:flex-end;gap:8px;margin-top:24px}[data-theme=dark] .error,[data-theme=dark] .required{color:#ff99a4}footer{padding:0 24px 20px;text-align:center;font-size:12px;color:var(--colorNeutralForeground3)}@media(max-width:700px){.page{padding:16px}.topbar{padding:12px 16px}.top-note{display:none}.layout{grid-template-columns:1fr}.document,.people{padding:20px}.aside{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px}.aside h2,.aside hr{grid-column:1/-1}.aside hr{margin:0}.heading{align-items:flex-start}.heading .primary{flex:none}.member{flex-wrap:wrap}.member .tag{margin-left:44px}.topbar button,.heading button{min-height:40px}}@media(max-width:420px){h1{font-size:20px;line-height:28px}.heading{flex-direction:column;gap:12px}.aside{display:block}.member .tag{margin-left:0}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}
</style></head><body>
<header class="topbar"><div class="brand"><span class="mark" aria-hidden="true"><i></i><i></i><i></i><i></i></span>Northstar workspace <span class="top-note">/ Product team</span></div><button id="theme" aria-pressed="false">Dark theme</button></header>
<main class="page"><div class="heading"><div><div class="eyebrow">Team workspace · October launch</div><h1>Launch workspace</h1><p class="muted">One brief. A clear decision. The right people.</p></div><button class="primary" id="share">Add a person</button></div>
<div class="tabs" role="tablist" aria-label="Workspace views"><button class="tab" id="brief-tab" role="tab" aria-controls="brief-panel" aria-selected="true" tabindex="0">Brief</button><button class="tab" id="people-tab" role="tab" aria-controls="people-panel" aria-selected="false" tabindex="-1">People <span id="count">2</span></button></div>
<section id="brief-panel" role="tabpanel" aria-labelledby="brief-tab" tabindex="0"><div class="layout"><article class="document"><div class="docmeta"><span class="avatar" aria-hidden="true">AC</span><span>Alex Chen · Product design<br>Updated today at 09:30</span></div><h2>A more welcoming first project</h2><p>Help a new team move from an empty workspace to its first useful result. This review focuses on the welcome screen and the first-project setup.</p><h3>The decision</h3><div class="quote">Should a sample project be created automatically, or offered as an option?</div><p>We want a clear starting point without filling the workspace with content someone did not choose. Review both paths before the team walkthrough.</p><h3>Review checklist</h3><ul class="checklist"><li><input id="c1" type="checkbox" checked><label for="c1">Welcome copy explains the next step</label></li><li><input id="c2" type="checkbox"><label for="c2">Empty workspace offers a sample project</label></li><li><input id="c3" type="checkbox"><label for="c3">Keyboard path reaches the first project action</label></li></ul><p class="small muted">Checklist changes are local to this example.</p></article><aside class="aside"><h2>Working together</h2><div class="person"><span class="avatar" aria-hidden="true">AC</span><div><p>Alex Chen</p><span class="small muted">Workspace owner</span></div></div><div class="person"><span class="avatar" aria-hidden="true">MP</span><div><p>Maya Patel</p><span class="small muted">Can edit</span></div></div><hr><div><h3>Next review</h3><p>Thursday, 10:00<br><span class="muted small">Team walkthrough · UTC</span></p></div><div><h3>Access</h3><span class="tag">Specific people</span><p class="small muted" style="margin-top:8px">Adding a person here updates only this local preview.</p></div></aside></div></section>
<section id="people-panel" role="tabpanel" aria-labelledby="people-tab" tabindex="0" hidden><div class="people"><div class="people-head"><h2>People with access</h2><span class="tag">Local example</span></div><p class="muted">The roles below are fictional. No invitation or real access change is made.</p><ul id="members"><li class="member"><span class="avatar" aria-hidden="true">AC</span><div class="member-info"><p>Alex Chen</p><span class="small muted">alex@example.com</span></div><span class="tag">Owner</span></li><li class="member"><span class="avatar" aria-hidden="true">MP</span><div class="member-info"><p>Maya Patel</p><span class="small muted">maya@example.com</span></div><span class="tag">Can edit</span></li></ul></div></section><p class="status" id="status" role="status"></p><p class="caption">Fluent UI React v9 web-token study · HTML/CSS interpretation, not native library components. Try tabs, theme, checkboxes and the access form.</p></main>
<dialog id="access" aria-labelledby="dialog-title"><form id="access-form" novalidate><h2 id="dialog-title">Add a person to Launch workspace</h2><p class="muted">Choose an address and permission. This demonstration updates the local list only.</p><div class="field"><label for="email">Email address <span class="required" aria-hidden="true">*</span></label><input id="email" type="email" autocomplete="email" aria-required="true" aria-describedby="email-hint" autofocus><div class="hint" id="email-hint">For example, jordan@example.com</div><div class="error" id="error" role="alert" hidden></div></div><div class="field"><label for="permission">Permission</label><select id="permission" aria-describedby="permission-hint"><option>Can view</option><option>Can edit</option></select><div class="hint" id="permission-hint">Viewers can read; editors can change the brief in a real application</div></div><div class="actions"><button type="button" id="cancel">Cancel</button><button class="primary" type="submit">Add locally</button></div></form></dialog>
<script>
const $=id=>document.getElementById(id),tabs=[...document.querySelectorAll('[role=tab]')],emails=new Set(['alex@example.com','maya@example.com']);
function selectTab(tab){tabs.forEach(t=>{const chosen=t===tab;t.setAttribute('aria-selected',String(chosen));t.tabIndex=chosen?0:-1;$(t.getAttribute('aria-controls')).hidden=!chosen;});}
tabs.forEach((tab,index)=>{tab.addEventListener('click',()=>selectTab(tab));tab.addEventListener('keydown',event=>{let next;if(event.key==='ArrowRight')next=(index+1)%tabs.length;if(event.key==='ArrowLeft')next=(index+tabs.length-1)%tabs.length;if(event.key==='Home')next=0;if(event.key==='End')next=tabs.length-1;if(next!==undefined){event.preventDefault();tabs.forEach(t=>t.tabIndex=-1);tabs[next].tabIndex=0;tabs[next].focus();}});});
$('theme').onclick=()=>{const dark=document.documentElement.dataset.theme!=='dark';document.documentElement.dataset.theme=dark?'dark':'light';$('theme').textContent=dark?'Light theme':'Dark theme';$('theme').setAttribute('aria-pressed',String(dark));};
const dialog=$('access'),email=$('email'),error=$('error');function clearError(){error.hidden=true;error.textContent='';email.removeAttribute('aria-invalid');email.setAttribute('aria-describedby','email-hint');}function showError(message){error.textContent=message;error.hidden=false;email.setAttribute('aria-invalid','true');email.setAttribute('aria-describedby','email-hint error');email.focus();}
$('share').onclick=()=>{clearError();dialog.showModal();email.focus();};$('cancel').onclick=()=>dialog.close();dialog.addEventListener('close',()=>$('share').focus());dialog.addEventListener('click',event=>{if(event.target===dialog){const r=dialog.getBoundingClientRect();if(event.clientX<r.left||event.clientX>r.right||event.clientY<r.top||event.clientY>r.bottom)dialog.close();}});email.addEventListener('input',clearError);
$('access-form').addEventListener('submit',event=>{event.preventDefault();const value=email.value.trim().toLowerCase();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)){showError('Enter an email address such as name@example.com');return;}if(emails.has(value)){showError('This address already appears in the local access list');return;}const permission=$('permission').value;emails.add(value);const item=document.createElement('li');item.className='member';const avatar=document.createElement('span');avatar.className='avatar';avatar.setAttribute('aria-hidden','true');avatar.textContent=value.slice(0,2).toUpperCase();const info=document.createElement('div');info.className='member-info';const name=document.createElement('p');name.textContent=value;const sub=document.createElement('span');sub.className='small muted';sub.textContent='Added in this local example';info.append(name,sub);const role=document.createElement('span');role.className='tag';role.textContent=permission;item.append(avatar,info,role);$('members').append(item);$('count').textContent=emails.size;$('status').textContent='Added '+value+' as '+permission.toLowerCase()+' locally. No invitation was sent.';email.value='';clearError();selectTab($('people-tab'));dialog.close();});
</script></body></html>
```

Code-Referenz

- Der Zugriffsdialog und die Tabs in diesem Dokument verwenden native HTML-Steuerelemente. Führen Sie den separaten Einstiegspunkt für React v9 aus, um das Verhalten von FluentProvider, Field und Dialog zu bewerten.

### Vollständiger Einstieg für die native Implementierung

Die vollständige Implementierung aus dem Setup, hier zusammen mit den gezielten Erläuterungen zu API zusammengestellt. Beachte die in den Setup-Anweisungen dokumentierten Voraussetzungen für Pakete und Builds.

```
// Terminal: npm install @fluentui/react-components@9
// Existing React application; index.html must contain <div id="root"></div>.
// Entry file: src/main.jsx
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import {
  FluentProvider, webLightTheme, webDarkTheme, makeStyles, tokens,
  Button, Body1, Title3, TabList, Tab, Field, Input, Select,
  Dialog, DialogTrigger, DialogSurface, DialogBody, DialogTitle,
  DialogContent, DialogActions
} from '@fluentui/react-components';

const useStyles = makeStyles({
  page: { maxWidth: '880px', margin: '0 auto', padding: tokens.spacingHorizontalXXL },
  header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: tokens.spacingHorizontalL },
  panel: { padding: tokens.spacingHorizontalXXL, marginTop: tokens.spacingVerticalL,
    backgroundColor: tokens.colorNeutralBackground2, borderRadius: tokens.borderRadiusXLarge },
  form: { display: 'grid', gap: tokens.spacingVerticalL },
  row: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: tokens.spacingHorizontalM,
    paddingTop: tokens.spacingVerticalM, paddingBottom: tokens.spacingVerticalM },
});

function Workspace({ dark, setDark }) {
  const styles = useStyles();
  const [tab, setTab] = React.useState('brief');
  const [open, setOpen] = React.useState(false);
  const [email, setEmail] = React.useState('');
  const [permission, setPermission] = React.useState('Can view');
  const [error, setError] = React.useState('');
  const [notice, setNotice] = React.useState('');
  const [people, setPeople] = React.useState([{ email: 'alex@example.com', permission: 'Owner' }]);
  function submit(event) {
    event.preventDefault();
    const value = email.trim().toLowerCase();
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      setError('Enter an email address such as name@example.com'); return;
    }
    if (people.some(person => person.email === value)) {
      setError('This address already appears in the local access list'); return;
    }
    setPeople(previous => [...previous, { email: value, permission }]);
    setNotice(`Added ${value} as ${permission.toLowerCase()} in this local example. No invitation was sent.`);
    setEmail(''); setError(''); setOpen(false); setTab('people');
  }
  return <main className={styles.page}>
    <div className={styles.header}>
      <Title3 as="h1">Launch workspace</Title3>
      <Button onClick={() => setDark(!dark)}>{dark ? 'Light theme' : 'Dark theme'}</Button>
    </div>
    <Body1>Project brief and access settings · local demonstration</Body1>
    <TabList aria-label="Workspace views" selectedValue={tab}
      onTabSelect={(_, data) => setTab(data.value)}>
      <Tab id="brief-tab" value="brief" aria-controls="brief-panel">Brief</Tab>
      <Tab id="people-tab" value="people" aria-controls="people-panel">People</Tab>
    </TabList>
    <section id="brief-panel" role="tabpanel" aria-labelledby="brief-tab"
      hidden={tab !== 'brief'} className={styles.panel} tabIndex={0}>
      <h2>Launch a clearer onboarding flow</h2>
      <p>Review the welcome screen and first-project setup before the team walkthrough.</p>
      <p>Decision needed: should the sample project be created automatically or offered as an option?</p>
    </section>
    <section id="people-panel" role="tabpanel" aria-labelledby="people-tab"
      hidden={tab !== 'people'} className={styles.panel} tabIndex={0}>
      <h2>People with access</h2>
      <ul>{people.map(person => <li key={person.email} className={styles.row}>
        <span>{person.email}</span><strong>{person.permission}</strong>
      </li>)}</ul>
    </section>
    <Dialog open={open} onOpenChange={(_, data) => setOpen(data.open)}>
      <DialogTrigger disableButtonEnhancement><Button appearance="primary">Add a person</Button></DialogTrigger>
      <DialogSurface>
        <form noValidate onSubmit={submit}>
          <DialogBody>
            <DialogTitle>Add a person to Launch workspace</DialogTitle>
            <DialogContent className={styles.form}>
              <p>This example updates local state only. It does not send email or change real access.</p>
              <Field label="Email address" required validationState={error ? 'error' : 'none'}
                validationMessage={error || undefined}>
                <Input type="email" value={email} onChange={(_, data) => { setEmail(data.value); setError(''); }} />
              </Field>
              <Field label="Permission" hint="Viewers can read; editors can change the brief in a real application">
                <Select value={permission} onChange={(_, data) => setPermission(data.value)}>
                  <option>Can view</option><option>Can edit</option>
                </Select>
              </Field>
            </DialogContent>
            <DialogActions>
              <DialogTrigger disableButtonEnhancement><Button type="button">Cancel</Button></DialogTrigger>
              <Button type="submit" appearance="primary">Add locally</Button>
            </DialogActions>
          </DialogBody>
        </form>
      </DialogSurface>
    </Dialog>
    <p role="status">{notice}</p>
  </main>;
}
function App() {
  const [dark, setDark] = React.useState(false);
  return <FluentProvider theme={dark ? webDarkTheme : webLightTheme}>
    <Workspace dark={dark} setDark={setDark} />
  </FluentProvider>;
}
createRoot(document.getElementById('root')).render(<App />);
```

Code-Referenz

- Vollständige Komponentenzusammenstellung für React v9 in einer bestehenden React-App. Die eigenständige Vorschau ist eine separate Umsetzung mit HTML/CSS. Dieser Code führt nur lokale Validierungen und Statusaktualisierungen aus; E-Mails werden nicht versendet und Berechtigungen nicht tatsächlich geändert. Die Quell-APIs wurden überprüft. Eine erfolgreiche Kompilierung des nativen Pakets wird erst behauptet, wenn sie im Zielprojekt getestet wurde.

### Field + Input + Select: ein Zugriffsformular mit Beschriftung

Diese Codeausschnitte verwenden die Statusvariablen und Imports aus der vollständigen Einrichtung weiter unten. Field übernimmt die Darstellung von Beschriftung, Hinweis und Validierung; die Anwendung ist für die E-Mail-Regel und die Duplikatprüfung zuständig.

```
<Field label="Email address" required
  validationState={error ? 'error' : 'none'}
  validationMessage={error || undefined}>
  <Input type="email" value={email}
    onChange={(_, data) => { setEmail(data.value); setError(''); }} />
</Field>
<Field label="Permission" hint="Choose what this person can do">
  <Select value={permission}
    onChange={(_, data) => setPermission(data.value)}>
    <option>Can view</option><option>Can edit</option>
  </Select>
</Field>
```

Code-Referenz

- required sorgt für einen barrierefreien Hinweis auf die Pflichtangabe; die Validierungsregel der Anwendung wird dadurch nicht implementiert.

- Der Standardzustand der Validierung wechselt zu error, wenn validationMessage vorhanden ist. Setzen Sie ihn ausdrücklich auf none, wenn kein Fehler angezeigt werden soll.

- Input onChange stellt die aktuelle Zeichenfolge in data.value bereit. Verwechseln Sie den Handler nicht mit einem Eingabefeld, das ausschließlich ein einfaches DOM-Ereignis verwendet.

### Kontrollierte TabList mit ausdrücklich verknüpften Panels

TabList steuert Auswahl und Tab-Verhalten. Rendern Sie die Inhaltspanels selbst und verknüpfen Sie deren IDs und barrierefreie Namen mit den jeweiligen Tabs.

```
<TabList selectedValue={tab} aria-label="Workspace views"
  onTabSelect={(_, data) => setTab(data.value)}>
  <Tab id="brief-tab" value="brief" aria-controls="brief-panel">Brief</Tab>
  <Tab id="people-tab" value="people" aria-controls="people-panel">People</Tab>
</TabList>
<section id="brief-panel" role="tabpanel" aria-labelledby="brief-tab"
  hidden={tab !== 'brief'} tabIndex={0}>Project brief</section>
<section id="people-panel" role="tabpanel" aria-labelledby="people-tab"
  hidden={tab !== 'people'} tabIndex={0}>People with access</section>
```

Code-Referenz

- selectedValue gehört auf TabList; jeder Tab benötigt einen eigenen Wert.

- selectTabOnFocus ist standardmäßig auf false gesetzt. Fokuswechsel mit den Pfeiltasten und Aktivierung sind getrennte Vorgänge, sofern dieses Verhalten nicht ausdrücklich geändert wird.

- Horizontale Fluent-Tabs laufen nicht automatisch um und scrollen auch nicht automatisch. Das Beispiel verwendet zwei kurze Beschriftungen, damit beide sichtbar bleiben.

## Microsoft Fluent 2-Designsystem: Einrichtung des AI-Agenten

### Ausgangspunkt für die Implementierung

Vollständige Komponentenzusammenstellung für React v9 in einer bestehenden React-App. Die eigenständige Vorschau ist eine separate Umsetzung mit HTML/CSS. Dieser Code führt nur lokale Validierungen und Statusaktualisierungen aus; E-Mails werden nicht versendet und Berechtigungen nicht tatsächlich geändert. Die Quell-APIs wurden überprüft. Eine erfolgreiche Kompilierung des nativen Pakets wird erst behauptet, wenn sie im Zielprojekt getestet wurde.

```
// Terminal: npm install @fluentui/react-components@9
// Existing React application; index.html must contain <div id="root"></div>.
// Entry file: src/main.jsx
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import {
  FluentProvider, webLightTheme, webDarkTheme, makeStyles, tokens,
  Button, Body1, Title3, TabList, Tab, Field, Input, Select,
  Dialog, DialogTrigger, DialogSurface, DialogBody, DialogTitle,
  DialogContent, DialogActions
} from '@fluentui/react-components';

const useStyles = makeStyles({
  page: { maxWidth: '880px', margin: '0 auto', padding: tokens.spacingHorizontalXXL },
  header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: tokens.spacingHorizontalL },
  panel: { padding: tokens.spacingHorizontalXXL, marginTop: tokens.spacingVerticalL,
    backgroundColor: tokens.colorNeutralBackground2, borderRadius: tokens.borderRadiusXLarge },
  form: { display: 'grid', gap: tokens.spacingVerticalL },
  row: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: tokens.spacingHorizontalM,
    paddingTop: tokens.spacingVerticalM, paddingBottom: tokens.spacingVerticalM },
});

function Workspace({ dark, setDark }) {
  const styles = useStyles();
  const [tab, setTab] = React.useState('brief');
  const [open, setOpen] = React.useState(false);
  const [email, setEmail] = React.useState('');
  const [permission, setPermission] = React.useState('Can view');
  const [error, setError] = React.useState('');
  const [notice, setNotice] = React.useState('');
  const [people, setPeople] = React.useState([{ email: 'alex@example.com', permission: 'Owner' }]);
  function submit(event) {
    event.preventDefault();
    const value = email.trim().toLowerCase();
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      setError('Enter an email address such as name@example.com'); return;
    }
    if (people.some(person => person.email === value)) {
      setError('This address already appears in the local access list'); return;
    }
    setPeople(previous => [...previous, { email: value, permission }]);
    setNotice(`Added ${value} as ${permission.toLowerCase()} in this local example. No invitation was sent.`);
    setEmail(''); setError(''); setOpen(false); setTab('people');
  }
  return <main className={styles.page}>
    <div className={styles.header}>
      <Title3 as="h1">Launch workspace</Title3>
      <Button onClick={() => setDark(!dark)}>{dark ? 'Light theme' : 'Dark theme'}</Button>
    </div>
    <Body1>Project brief and access settings · local demonstration</Body1>
    <TabList aria-label="Workspace views" selectedValue={tab}
      onTabSelect={(_, data) => setTab(data.value)}>
      <Tab id="brief-tab" value="brief" aria-controls="brief-panel">Brief</Tab>
      <Tab id="people-tab" value="people" aria-controls="people-panel">People</Tab>
    </TabList>
    <section id="brief-panel" role="tabpanel" aria-labelledby="brief-tab"
      hidden={tab !== 'brief'} className={styles.panel} tabIndex={0}>
      <h2>Launch a clearer onboarding flow</h2>
      <p>Review the welcome screen and first-project setup before the team walkthrough.</p>
      <p>Decision needed: should the sample project be created automatically or offered as an option?</p>
    </section>
    <section id="people-panel" role="tabpanel" aria-labelledby="people-tab"
      hidden={tab !== 'people'} className={styles.panel} tabIndex={0}>
      <h2>People with access</h2>
      <ul>{people.map(person => <li key={person.email} className={styles.row}>
        <span>{person.email}</span><strong>{person.permission}</strong>
      </li>)}</ul>
    </section>
    <Dialog open={open} onOpenChange={(_, data) => setOpen(data.open)}>
      <DialogTrigger disableButtonEnhancement><Button appearance="primary">Add a person</Button></DialogTrigger>
      <DialogSurface>
        <form noValidate onSubmit={submit}>
          <DialogBody>
            <DialogTitle>Add a person to Launch workspace</DialogTitle>
            <DialogContent className={styles.form}>
              <p>This example updates local state only. It does not send email or change real access.</p>
              <Field label="Email address" required validationState={error ? 'error' : 'none'}
                validationMessage={error || undefined}>
                <Input type="email" value={email} onChange={(_, data) => { setEmail(data.value); setError(''); }} />
              </Field>
              <Field label="Permission" hint="Viewers can read; editors can change the brief in a real application">
                <Select value={permission} onChange={(_, data) => setPermission(data.value)}>
                  <option>Can view</option><option>Can edit</option>
                </Select>
              </Field>
            </DialogContent>
            <DialogActions>
              <DialogTrigger disableButtonEnhancement><Button type="button">Cancel</Button></DialogTrigger>
              <Button type="submit" appearance="primary">Add locally</Button>
            </DialogActions>
          </DialogBody>
        </form>
      </DialogSurface>
    </Dialog>
    <p role="status">{notice}</p>
  </main>;
}
function App() {
  const [dark, setDark] = React.useState(false);
  return <FluentProvider theme={dark ? webDarkTheme : webLightTheme}>
    <Workspace dark={dark} setDark={setDark} />
  </FluentProvider>;
}
createRoot(document.getElementById('root')).render(<App />);
```

### Ein Prompt für dein Projekt

```
Verwende Fluent UI React v9 aus @fluentui/react-components. Rendere FluentProvider mit webLightTheme und einem Umschalter für webDarkTheme. Stelle die Kurzbeschreibung mit Title3 und Body1 zusammen, verwende eine gesteuerte TabList mit Ansichten und expliziten Panels sowie einen Dialog für Zugriffsrechte mit Field/Input/Select und einem echten Formular. Verwende Tokens für individuelle Oberflächen und Abstände. Folge dem bereitgestellten Komponentenbeispiel und den Laufzeit-Typ-Paaren, einschließlich Subtitle1 mit 20/28. Erhalte ungültige Eingaben, weise doppelte lokale Adressen zurück, stelle den Fokus nach dem Dialog wieder her und beschreibe lokal hinzugefügte Einträge korrekt. Binde einen Freigabedienst nur ein, wenn dessen Autorisierung und Ergebniskontrakt vorliegen.
```

## Quellen und Geltungsbereich des Microsoft Fluent 2-Designsystems

Eine OpenDesign-Anwendungsstudie zu Fluent UI React v9, kein Microsoft-Produkt und kein aktiver Freigabedienst. Die eigenständige Vorschau ist eine HTML/CSS-Interpretation verifizierter Web-Tokens und der Komponentenstruktur; der React-Code unten verwendet native Fluent-Komponenten. Die Referenzwerte entsprechen dem verknüpften Quellstand, der am 3. Oktober 2026 geprüft wurde, und sind keine Zusicherung, dass alle Versionen, Plattformen oder Marken identische Werte verwenden.

- Paketeinstiegspunkt für React v9 Provider- und Suite-Installation.

- Theme-Architektur Semantische Token-Verwendung und verfügbare Themes.

- Laufzeit-Typografie Schriftfamilie, Schriftgröße, Zeilenhöhe und Schriftstärken.

- Zuordnung der Textstile Voreinstellungen, globalen Tokens zugeordnet.

- Design-Typografieskala Tabelle der Designsprache; Subtitle1 weicht vom Laufzeit-Paar ab.

- Laufzeit-Abstände Horizontale und vertikale Token-Namen.

- Layout-Richtlinien Globale Abstände und Aspekte des responsiven Designs.

- Radius-Tokens Verfügbare Formwerte zur Laufzeit.

- Animationsdauer Dauerwerte zur Laufzeit.

- Semantische Zuordnung für helle Themes Zuordnungen von Neutral- und Markenaliasen.

- Semantische Zuordnung für dunkle Themes Aliaszuordnungen für dunkle Themes.

- Markenfarbskalen Tatsächliche Markenwerte für Web und Teams.

- Erstellung des Web-Themes webLightTheme verwendet brandWeb.

- Verwendung von Field Richtlinien zu Labels, Validierung und Zusammensetzung.

- Field API Slots und Vertrag für barrierefreie untergeordnete Elemente.

- Verwendung von TabList Richtlinien zu Layout und Kategorieauswahl.

- TabList API Gesteuerte Auswahl und Fokusoptionen.

- Verwendung von Dialog Richtlinien zur Formularplatzierung und modalen Interaktion.

- Dialog API Gesteuerte Sichtbarkeit und modale Typen.

## Weitere Ressourcen zum Microsoft Fluent 2-Designsystem

### Monday Vibe

Erstelle mit Vibe-4-Tokens und React-Steuerelementen ein funktionsfähiges Lieferboard. Erfahre, worin sich semantische Aktionsfarben und Board-Beschriftungen unterscheiden, wie benannte Abstandsstufen und Schrift-Kurzschreibweisen funktionieren und welche explizite Einrichtung von CSS eine neue Anwendung benötigt.

### Morningstar Designsystem

Erstellen Sie eine Rechercheoberfläche, in der Zahlen bündig ausgerichtet sind, Asset-Farben ihre Bedeutung behalten und die Typografie gut lesbar bleibt. Entdecken Sie MDS-Konstanten, die Integration mit Vue 3, den Übergang zu Morningstar Intrinsic und ein sortierbares, fiktives Allokationsnotizbuch.

### Mozilla Protocol

Ein redaktioneller Leitfaden zu Protocol mit echten Schriftfamilien, Abstands- und Container-Skalen, einer responsiven, illustrierten Leseseite und einem vollständigen Formularbeispiel mit nativen CSS-Komponenten.


- [Implementierungsreferenz](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-components/README.md)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/lightColor.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/brandColors.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/spacings.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/borderRadius.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/durations.ts)
- [Quelle](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/darkColor.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-components/README.md)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/docs/architecture/design-tokens.md)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/lightColor.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/darkColor.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/typographyStyles.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/spacings.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/borderRadius.ts)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-tabs/library/src/components/TabList/TabList.types.ts)
- [Unterstützende Spezifikation lesen](https://fluent2.microsoft.design/components/web/react/core/tablist/usage)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-field/library/src/components/Field/Field.types.ts)
- [Unterstützende Spezifikation lesen](https://fluent2.microsoft.design/components/web/react/core/field/usage)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-dialog/library/src/components/Dialog/Dialog.types.ts)
- [Unterstützende Spezifikation lesen](https://fluent2.microsoft.design/components/web/react/core/dialog/usage)
- [Unterstützende Spezifikation lesen](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/durations.ts)
- [Code-Referenz](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-components/README.md)
- [Code-Referenz](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-field/library/src/components/Field/Field.types.ts)
- [Code-Referenz](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-tabs/library/src/components/TabList/TabList.types.ts)
- [Paketeinstiegspunkt für React v9 Provider- und Suite-Installation.](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-components/README.md)
- [Theme-Architektur Semantische Token-Verwendung und verfügbare Themes.](https://github.com/microsoft/fluentui/blob/master/docs/architecture/design-tokens.md)
- [Laufzeit-Typografie Schriftfamilie, Schriftgröße, Zeilenhöhe und Schriftstärken.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts)
- [Zuordnung der Textstile Voreinstellungen, globalen Tokens zugeordnet.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/typographyStyles.ts)
- [Design-Typografieskala Tabelle der Designsprache; Subtitle1 weicht vom Laufzeit-Paar ab.](https://fluent2.microsoft.design/typography)
- [Laufzeit-Abstände Horizontale und vertikale Token-Namen.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/spacings.ts)
- [Layout-Richtlinien Globale Abstände und Aspekte des responsiven Designs.](https://fluent2.microsoft.design/layout)
- [Radius-Tokens Verfügbare Formwerte zur Laufzeit.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/borderRadius.ts)
- [Animationsdauer Dauerwerte zur Laufzeit.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/durations.ts)
- [Semantische Zuordnung für helle Themes Zuordnungen von Neutral- und Markenaliasen.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/lightColor.ts)
- [Semantische Zuordnung für dunkle Themes Aliaszuordnungen für dunkle Themes.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/alias/darkColor.ts)
- [Markenfarbskalen Tatsächliche Markenwerte für Web und Teams.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/brandColors.ts)
- [Erstellung des Web-Themes webLightTheme verwendet brandWeb.](https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/themes/web/lightTheme.ts)
- [Verwendung von Field Richtlinien zu Labels, Validierung und Zusammensetzung.](https://fluent2.microsoft.design/components/web/react/core/field/usage)
- [Field API Slots und Vertrag für barrierefreie untergeordnete Elemente.](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-field/library/src/components/Field/Field.types.ts)
- [Verwendung von TabList Richtlinien zu Layout und Kategorieauswahl.](https://fluent2.microsoft.design/components/web/react/core/tablist/usage)
- [TabList API Gesteuerte Auswahl und Fokusoptionen.](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-tabs/library/src/components/TabList/TabList.types.ts)
- [Verwendung von Dialog Richtlinien zur Formularplatzierung und modalen Interaktion.](https://fluent2.microsoft.design/components/web/react/core/dialog/usage)
- [Dialog API Gesteuerte Sichtbarkeit und modale Typen.](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-dialog/library/src/components/Dialog/Dialog.types.ts)
