---
title: "Komponenten — zenit Zig UI Doku"
description: "Was eine zenit-Komponente verspricht, wann Sie eine Ebene tiefer gehen sollten, und die drei Verträge — Mounting, Overlays und Tests."
url: https://zenit.z.express/de/docs/guide/components
language: de
alternate_en: https://zenit.z.express/docs/guide/components.md
alternate_zh: https://zenit.z.express/zh/docs/guide/components.md
alternate_es: https://zenit.z.express/es/docs/guide/components.md
alternate_ja: https://zenit.z.express/ja/docs/guide/components.md
alternate_ko: https://zenit.z.express/ko/docs/guide/components.md
alternate_fr: https://zenit.z.express/fr/docs/guide/components.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# Komponenten

Was eine zenit-Komponente verspricht, wann Sie eine Ebene tiefer gehen sollten, und die drei Verträge — Mounting, Overlays und Tests. Aufnahmen, Props und Ergebnistypen jeder Komponente finden Sie auf der [Komponenten-Website](https://zenit.z.express/de/components).

## Was „Komponente“ hier bedeutet

Eine zenit-Komponente ist kein Helper, der Farben und Eckradien zusammenklebt. Eine öffentliche Komponente bündelt typischerweise Knotenstruktur, persistenten Zustand, Event-Routing, Fokus- und Tastatursemantik, Barrierefreiheitseigenschaften, Theme-Tokens, Overlay-Lebensdauer und eine Testgrenze, die der Harness finden und zurücklesen kann. Alle werden aus `ui.widgets` exportiert.

**51**Stories auf der Komponenten-Website

**6**Anwendungskategorien (plus Labs)

**1:1**Story zu E2E-test\_id

ANATOMY

mount erzeugt zuerst einen Kind-Scope; alles, was er besitzt, wird zusammen mit dem Eltern-Scope freigegeben.

## Zuerst die richtige Ebene wählen

| Bedarf | Ebene | Bleibt Ihre Aufgabe |
| --- | --- | --- |
| Standard-Bedienelemente | `ui.widgets.*` | Geschäftszustand, Texte, Callbacks und Platzierung |
| Eigene Optik, bewährte Interaktion | `ui.hooks` · `ui.interaction` · `ui.select_headless` | Zeichnen, Tokens, a11y-Labels und Kompositionsgrenzen |
| Ein neues Interaktionsmuster | `ui.Node` + `ui.events` | Hit-Testing, Tastatur, Fokus, IME, a11y und Testvertrag |

> TIP
> 
> **Beginnen Sie mit Widgets.** Gehen Sie nur dann eine Ebene tiefer, wenn das Verhaltensmodell einer vorhandenen Komponente nicht passt. Eine andere Optik rechtfertigt selten, Fokus, IME, Overlay-Schließen und Barrierefreiheit neu zu implementieren.

## Katalog

Jede Komponente hat eine eigene Seite auf der [Komponenten-Website](https://zenit.z.express/de/components): eine Aufnahme der echten `zenit Storybook.app`, aus dem Quellcode generierte Props und Ergebnistypen sowie das, was die Aufnahme belegt. Der Harness findet jede Story über ihre `test_id`, steuert einen virtuellen Cursor oder Eingaben und nimmt das Metal-Drawable direkt auf.

| Kategorie | Anzahl | Beispiele |
| --- | --- | --- |
| Aktionen | 7 | [Button](https://zenit.z.express/de/components/button) · [Checkbox](https://zenit.z.express/de/components/checkbox) · [Switch](https://zenit.z.express/de/components/switch) · [RadioGroup](https://zenit.z.express/de/components/radio) · [Slider](https://zenit.z.express/de/components/slider) … |
| Eingaben | 10 | [Input](https://zenit.z.express/de/components/input) · [Textarea](https://zenit.z.express/de/components/textarea) · [Select](https://zenit.z.express/de/components/select) · [Input · Select · Button](https://zenit.z.express/de/components/formcompose) · [ComboBox](https://zenit.z.express/de/components/combobox) … |
| Anzeige | 17 | [Badge](https://zenit.z.express/de/components/badge) · [Tag](https://zenit.z.express/de/components/tag) · [Chip](https://zenit.z.express/de/components/chip) · [Card](https://zenit.z.express/de/components/card) · [Alert](https://zenit.z.express/de/components/alert) … |
| Navigation | 4 | [Tabs](https://zenit.z.express/de/components/tabs) · [Accordion](https://zenit.z.express/de/components/accordion) · [Menu](https://zenit.z.express/de/components/menu) · [DropdownMenu](https://zenit.z.express/de/components/dropdown) |
| Overlays | 5 | [Notifier](https://zenit.z.express/de/components/notification) · [Tooltip](https://zenit.z.express/de/components/tooltip) · [Popover](https://zenit.z.express/de/components/popover) · [Modal](https://zenit.z.express/de/components/modal) · [Sheet](https://zenit.z.express/de/components/sheet) |
| Layout | 8 | [GlassBox](https://zenit.z.express/de/components/glassbox) · [Divider](https://zenit.z.express/de/components/divider) · [HStack / VStack](https://zenit.z.express/de/components/stack) · [ui.box](https://zenit.z.express/de/components/layoutbox) · [VirtualList](https://zenit.z.express/de/components/virtuallist) … |
| Labs | 13 | [glasslab](https://zenit.z.express/de/components/glasslab) · [glassislands](https://zenit.z.express/de/components/glassislands) · [glassmotion](https://zenit.z.express/de/components/glassmotion) · [glasschrome](https://zenit.z.express/de/components/glasschrome) · [canvasevents](https://zenit.z.express/de/components/canvasevents) … |

[Video](https://zenit.z.express/media/stories/button.mp4?v=6203a01415)

Die Button-Story durchläuft die Matrix variant × size und zeigt dann Hover und Press auf Primary. Details unter [/components/button](https://zenit.z.express/de/components/button).

## Mount, Zustand & Aufräumen

Die meisten visuellen Komponenten nutzen die Builder-Form `Config.mount(scope, cx)`: `ui.widgets.Button(props)` gibt einen Builder zurück, und erst `mount` baut den Baum. Der Rückgabewert ist entweder der Wurzel-`*Node` oder eine Ergebnis-Struct mit Handles wie wrapper, trigger, body, panel und state.

`mount_form.zig`

```zig
const EditorActions = struct {
    document: *Document,

    fn save(self: *EditorActions) void {
        self.document.save();
    }
};

const bindings = try cx.bindState(EditorActions, .{ .document = document });

const save = try ui.widgets.Button(.{
    .label = "Save",
    .variant = .primary,
    .on_click = cx.on(EditorActions, bindings, EditorActions.save),
}).mount(scope, cx);

const name = try ui.widgets.Input(.{
    .label_text = "Project name",
    .placeholder = "Untitled",
    .required = true,
    .width = 320,
}).mount(scope, cx);

try form.appendChild(cx.allocator, name);
try form.appendChild(cx.allocator, save);
```

Einige Komponenten nutzen die Funktionsform und erhalten Props, Scope und cx in einem Aufruf: `mountScrollArea`, `mountGrid` sowie `Select`, `ComboBox`, `TagsInput`, `NumberStepper`, `FileUpload` und `DataTable` (das sind Aliase von `mountX`\-Funktionen in `ui.widgets`, aufgerufen als `ui.widgets.Select(props, scope, cx)`).

`scroll_area.zig`

```zig
// Function form: props, scope and cx in one call; returns a handle struct.
const area = try ui.widgets.mountScrollArea(.{ .height = 320 }, scope, cx);
try area.content.appendChild(cx.allocator, list);
try root.appendChild(cx.allocator, area.container);
```

| Komponente | Rückgabe |
| --- | --- |
| `Button` · `Input` | `*Node` |
| `Modal` | `ModalResult{ overlay, dialog, body, portaled }` |
| `Tooltip` | `TooltipResult{ wrapper, trigger, content }` |
| `Select` | `SelectMount{ wrapper, trigger, panel, state, is_open }` |
| `mountScrollArea` | `ScrollAreaResult{ container, content, state }` |
| `mountGrid` | `GridResult{ root, state }` |

Behandeln Sie die Config nicht als Live-Props, in die Sie später schreiben können. Eine Komponente liest ihre Config beim Mounten, um Knoten und Zustand aufzubauen — ein `signal.get()` in der Config wird nur einmal als Snapshot gelesen. Sich ständig ändernde Daten fließen über den zurückgegebenen State, ein Signal (etwa `.visible(sig)` von Modal) oder die öffentlichen Methoden der Komponente ein; halten Sie nie einen Zeiger auf eine temporäre Config über Frames hinweg. Der interne Zustand einer Komponente liegt im Kind-Scope, den mount erzeugt, und wird freigegeben, wenn der Eltern-Scope disposed wird.

## Warum Overlays Komponenten sein müssen

Tooltip, Popover, Menu, Modal, Sheet und der In-App-[Notifier](https://zenit.z.express/de/components/notification) registrieren alle eine Ebene beim `OverlayStack`. Ebenen mit Barrier (Modal / Sheet) werden in das fensterweite Portal (`WindowOverlayPortal` unter `cx.root`) umgehängt und entkommen so dem Overflow-Clipping aller Vorfahren. Z-Werte stammen aus semantischen Tiers — overlay 100, dialog 1000, toast 2000 (wo der Notifier liegt), tooltip 3000, das Devtools-Overlay fest bei 32000 — und ein aus einem anderen Overlay geöffnetes Overlay liegt stets über seinem Host. Absolute Positionierung und ein hoher z-index auf einer Box liefern nichts davon.

`modal.zig`

```zig
const visible = try scope.createSignal(bool, false);

const modal = try ui.widgets.Modal(.{
    .title = "Delete document?",
    .width = 420,
}).visible(visible).mount(scope, cx);

try modal.body.appendChild(cx.allocator, confirm_content);
// modal.portaled == true: the barrier already lives under the window-level
// portal. Do not append modal.overlay to the current tree.

// Open it from any handler:
visible.set(true);
```

OVERLAY PORTAL

Wo Sie mount aufrufen, entscheidet nicht, wo das Overlay gezeichnet wird: Die Barrier geht ins Portal, das Tier bestimmt z, und Escape läuft vom oberen Ende des Stapels abwärts bis zur ersten schließbaren Ebene.

-   **Klicks im Inneren** bleiben im Dialog / Panel und lösen nie outside-dismiss aus; ein Klick auf die Barrier schließt gemäß `close_on_overlay`.
    
-   **Escape** schließt nur das oberste Overlay; verschachtelte Ebenen werden eine nach der anderen abgebaut.
    
-   **Fokus**: Ein offenes Modal fängt den Fokus ein und fokussiert automatisch; beim Schließen wird der Fokus an die vorherige Stelle zurückgesetzt.
    
-   **Scope-Dispose** löst den Barrier-Teilbaum aktiv aus dem Portal, sodass beim Seitenwechsel nie eine unsichtbare Trefferebene zurückbleibt.
    
-   **Ausblend-Übergänge** halten das Overlay sichtbar, bis die Animation abgeschlossen ist, und setzen es dann aus — kein Sprung zum Endzustand.
    

Für nicht blockierende, app-weite Benachrichtigungen verwenden Sie `ui.widgets.Notifier` (ersetzt den alten ToastManager): `Notifier.init(scope, cx, .{})` registriert eine Ebene im toast-Tier und mountet, sofern das Fensterportal existiert, dort seinen fensterfüllenden Container (ist `portaled` false, hängen Sie `container` selbst an Ihre Wurzel). Danach gibt `show(.{ .tone = .success, .title = "Saved" })` eine ID zurück, `update` ändert eine Karte an Ort und Stelle und `dismiss` entfernt sie. Schließen, Ablauf und Button-Aktionen kommen als `Listener`\-Events zur App zurück; Verlauf, Nicht-stören und andere Logik einer Mitteilungszentrale gehören in die App.

[Video](https://zenit.z.express/media/stories/modal.mp4?v=f1b080996c)

Der Harness öffnet einen zentrierten Dialog und prüft, dass Klicks im Inneren ihn nicht schließen. [Modal](https://zenit.z.express/de/components/modal)

[Video](https://zenit.z.express/media/stories/tooltip.mp4?v=64c28daff2)

Ein virtueller Cursor fährt über den Trigger; die Blase landet im tooltip-Tier, ohne das Layout zu berühren. [Tooltip](https://zenit.z.express/de/components/tooltip)

## Der Showcase ist zugleich eine Regressionssuite

`e2e/storybook.test.ts` wechselt über `nav.<key>` zu jeder Story, sammelt den Text des Teilbaums, prüft, dass jeder erwartete Datenwert vorhanden ist, und erstellt dann einen Screenshot; interaktive Komponenten prüfen zusätzlich Zustand, Geometrie oder Pixel nach der Interaktion. Die Aufnahmen der Komponenten-Website nutzen dieselbe App und dieselben semantischen IDs, sodass Demo und Test nie in zwei Implementierungen auseinanderlaufen.

| Prüfung | Was sie erkennt |
| --- | --- |
| Text- / Zustands-Rücklesen | Leere Panels, Callbacks ohne Rückschreiben, falsche Filter- / Seitenwerte |
| Geometrie-Assertions | Padding-Boxen, Zentrierung im Portal, Randausrichtung von Sheet, Drag-Deltas |
| Pixel-Assertions | Leere GPU-Ebenen, Blend-Regressionen, graustufige Emoji, falsche z-Reihenfolge |
| Aufnahmen | Timing von Hover, Press, Cursor, IME, Scrollen und Einblendanimationen |

> WARNING
> 
> **Storybook ist nicht Ihre Fachkomponenten-Bibliothek.** Editoren, Dateibrowser, Befehlspaletten und Domänenmodelle gehören in die App. Die öffentliche Bibliothek verspricht nur wiederverwendbares Verhalten und visuelle Primitive.
