14 KiB
Komponenten-Referenz
Vollständige Dokumentation aller opt-in Klassen aus components.css.
Navigation
Top Navigation (.topnav)
Sticky Navigationsleiste mit Branding, Links und optionalem User-Dropdown.
<nav class="topnav">
<div class="topnav-inner">
<a class="topnav-brand" href="/">Brand</a>
<ul class="topnav-links">
<li><a href="/" class="active">Dashboard</a></li>
<li>
<button data-action="nav-dropdown">
Mehr <svg class="nav-chevron"><!-- Chevron SVG --></svg>
</button>
<div class="topnav-dropdown">
<a href="/settings">Einstellungen</a>
<a href="/profile">Profil</a>
</div>
</li>
</ul>
<div class="topnav-end">
<!-- Buttons, User-Dropdown, Theme-Toggle -->
</div>
<button class="topnav-burger" aria-label="Menü öffnen">☰</button>
</div>
<div class="topnav-mobile">
<!-- Mobile Links -->
</div>
</nav>
Modifier: .topnav-static — nicht sticky
Sidebar (.sidebar)
Feste Seitenleiste für App-Layouts. Wird mit .with-sidebar kombiniert.
<!-- Vor dem with-sidebar-Container -->
<div class="mobile-topbar">
<button id="sidebar-toggle" aria-label="Menü öffnen">☰</button>
<span>App Name</span>
</div>
<div id="sidebar-backdrop" class="sidebar-backdrop"></div>
<div class="with-sidebar">
<aside class="sidebar">
<div class="sidebar-header">
<a href="/" class="sidebar-brand">Brand</a>
</div>
<nav class="sidebar-nav">
<div class="sidebar-section">Hauptmenü</div>
<a href="/" class="active">
<svg><!-- Icon --></svg>
Dashboard
<span class="nav-count">4</span>
</a>
<details class="sidebar-group">
<summary><svg><!-- Icon --></svg> Gruppe</summary>
<div class="sidebar-group-items">
<a href="/unterseite">Unterseite</a>
</div>
</details>
</nav>
<div class="sidebar-footer">
<a href="/profil" class="sidebar-user">
<div class="avatar avatar-sm">AM</div>
<div class="sidebar-user-info">
<div class="sidebar-user-name">Anna Müller</div>
<div class="sidebar-user-role">Admin</div>
</div>
</a>
</div>
</aside>
<main class="stack stack-lg">
<!-- Seiteninhalt -->
</main>
</div>
Footer (.footer)
<!-- Einfach -->
<footer class="footer">
<div class="footer-inner">
<a class="footer-brand" href="/">Brand</a>
<ul class="footer-links">
<li><a href="/impressum">Impressum</a></li>
<li><a href="/datenschutz">Datenschutz</a></li>
</ul>
<p class="footer-copy">© 2025 Acme GmbH</p>
</div>
</footer>
<!-- Mehrspaltig -->
<footer class="footer footer-full">
<div class="footer-inner">
<div class="footer-col">
<p class="footer-col-title">Produkt</p>
<a href="/features">Features</a>
<a href="/pricing">Preise</a>
</div>
<div class="footer-col">
<p class="footer-col-title">Rechtliches</p>
<a href="/impressum">Impressum</a>
</div>
</div>
<div class="footer-bottom">
<span>© 2025 Acme GmbH</span>
<ul class="footer-social">
<li><a href="https://github.com/..."><svg><!-- GitHub Icon --></svg></a></li>
</ul>
</div>
</footer>
Breadcrumbs (.breadcrumbs)
<nav class="breadcrumbs" aria-label="Breadcrumb">
<ol>
<li><a href="/dashboard">Dashboard</a></li>
<li><a href="/projekte">Projekte</a></li>
<li><span aria-current="page">Einstellungen</span></li>
</ol>
</nav>
Horizontaler Navigationspfad. Auf schmalen Viewports horizontal scrollbar.
Buttons (.btn)
Alle Buttons benötigen .btn als Basisklasse plus eine Variante.
<!-- Varianten -->
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-success">Success</button>
<!-- Größen (Standardgröße ist keine Größenklasse = medium) -->
<button class="btn btn-primary btn-xs">XSmall</button>
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-lg">Large</button>
<button class="btn btn-primary btn-xl">XLarge</button>
<!-- Modifiers -->
<button class="btn btn-primary btn-full">Volle Breite</button>
<button class="btn btn-ghost btn-icon"><svg><!-- Icon --></svg></button>
<!-- Als Link -->
<a href="/ziel" class="btn btn-primary">Link-Button</a>
<!-- Disabled -->
<button class="btn btn-primary" disabled>Gesperrt</button>
<!-- Button Group -->
<div class="button-group" role="group">
<button class="btn btn-secondary">Liste</button>
<button class="btn btn-secondary">Board</button>
<button class="btn btn-secondary">Kalender</button>
</div>
<!-- Segmented Control (Radio-Basis, kein JS) -->
<div class="segmented" role="radiogroup">
<label class="segmented-option" for="r-tag">
<input class="segmented-input" type="radio" name="range" id="r-tag">
<span class="segmented-button">Tag</span>
</label>
<label class="segmented-option" for="r-woche">
<input class="segmented-input" type="radio" name="range" id="r-woche" checked>
<span class="segmented-button">Woche</span>
</label>
<label class="segmented-option" for="r-monat">
<input class="segmented-input" type="radio" name="range" id="r-monat">
<span class="segmented-button">Monat</span>
</label>
</div>
Badges (.badge)
<span class="badge badge-default">Standard</span>
<span class="badge badge-primary">Primär</span>
<span class="badge badge-success">Erfolg</span>
<span class="badge badge-warning">Warnung</span>
<span class="badge badge-danger">Fehler</span>
<span class="badge badge-info">Info</span>
<span class="badge badge-outline">Outline</span>
<!-- Mit Dot-Indikator -->
<span class="badge badge-success badge-dot">Live</span>
Cards (.card)
<div class="card">
<div class="card-header">
<h3>Titel</h3>
<span class="badge badge-success">Aktiv</span>
</div>
<div class="card-body">
Inhalt der Karte
</div>
<div class="card-footer">
<button class="btn btn-ghost btn-sm">Abbrechen</button>
<button class="btn btn-primary btn-sm">Aktion</button>
</div>
</div>
Varianten: .card-flat, .card-raised, .card-ghost
Hover-Effekt: .card.card-hover
Image Card:
<div class="card">
<div class="card-media">
<img src="..." alt="...">
</div>
<div class="card-body">
<h3>Titel</h3>
<p>Beschreibung</p>
</div>
</div>
Formulare
Basis-Eingabeelemente (input, select, textarea) werden classless gestylt.
Opt-in Klassen für Gruppierung und Zustände:
<div class="form-group">
<label for="email">E-Mail</label>
<input type="email" id="email" name="email">
<span class="form-hint">Wird für Login genutzt.</span>
</div>
<!-- Fehler-State -->
<div class="form-group">
<label for="pwd">Passwort</label>
<input type="password" id="pwd" class="error">
<span class="form-error">Mindestens 8 Zeichen.</span>
</div>
<!-- Mehrere Felder nebeneinander -->
<div class="form-row">
<div class="form-group">
<label for="vorname">Vorname</label>
<input type="text" id="vorname">
</div>
<div class="form-group">
<label for="nachname">Nachname</label>
<input type="text" id="nachname">
</div>
</div>
<!-- Input mit Prefix/Suffix -->
<div class="input-group">
<span class="input-group-prefix">https://</span>
<input type="text" placeholder="beispiel.de">
</div>
<div class="input-group">
<input type="text" placeholder="Betrag">
<span class="input-group-suffix">EUR</span>
</div>
Tabellen
Classless gestylt — kein Wrapper nötig für einfache Tabellen:
<table>
<thead>
<tr><th>Name</th><th>Status</th><th>Datum</th></tr>
</thead>
<tbody>
<tr><td>Anna Müller</td><td><span class="badge badge-success">Aktiv</span></td><td>2025-01-15</td></tr>
</tbody>
</table>
<!-- Mit Rahmen und horizontalem Scroll (z.B. auf Mobile) -->
<div class="table-wrap">
<table>...</table>
</div>
<!-- Modifier -->
<table class="table-striped">...</table>
<table class="table-compact">...</table>
Alerts
<div class="alert alert-info">
<svg class="alert-icon"><!-- Icon --></svg>
<div class="alert-content">
<p class="alert-title">Hinweis</p>
<p>Deine Änderungen werden gespeichert.</p>
</div>
</div>
Varianten: alert-info, alert-success, alert-warning, alert-danger
Modals
<!-- Struktur -->
<div class="modal-backdrop" id="mein-modal"
data-action="modal-backdrop">
<div class="modal">
<div class="modal-header">
<h3>Titel</h3>
<button class="btn btn-ghost btn-icon btn-sm"
data-action="modal-close" data-target="mein-modal">✕</button>
</div>
<div class="modal-body">Inhalt</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-action="modal-close" data-target="mein-modal">Abbrechen</button>
<button class="btn btn-primary">Bestätigen</button>
</div>
</div>
</div>
<button data-action="modal-open" data-target="mein-modal">Modal öffnen</button>
Größen: .modal-sm, .modal-lg, .modal-xl
Tabs
<div class="tabs">
<ul class="tab-list" role="tablist">
<li>
<button class="active" role="tab"
data-action="tab" data-target="panel-1">Tab 1</button>
</li>
<li>
<button role="tab"
data-action="tab" data-target="panel-2">Tab 2</button>
</li>
</ul>
<div id="panel-1" class="tab-panel active">Inhalt Tab 1</div>
<div id="panel-2" class="tab-panel">Inhalt Tab 2</div>
</div>
Dropdowns
<div class="dropdown" id="dd-aktionen">
<button class="btn btn-secondary" data-action="dropdown" data-target="dd-aktionen">
Aktionen
</button>
<div class="dropdown-menu">
<div class="dropdown-label">Aktionen</div>
<button class="dropdown-item">Bearbeiten</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item danger">Löschen</button>
</div>
</div>
Positionierung: .dropdown-menu-left, .dropdown-menu-top
Breite: .dropdown-wide
Spezielle Item-Typen:
<!-- Mit Beschreibung -->
<button class="dropdown-item dropdown-item-rich">
<div class="dropdown-item-title">Projekt</div>
<div class="dropdown-item-desc">Neue Projektmappe erstellen</div>
</button>
<!-- Checkbox/Filter -->
<button class="dropdown-item dropdown-item-check checked"
data-action="toggle-class" data-class="checked">
Aktiv
</button>
<!-- User-Header -->
<div class="dropdown-header">
<div class="avatar">AM</div>
<div>
<div class="dropdown-header-name">Anna Müller</div>
<div class="dropdown-header-sub">anna@beispiel.de</div>
</div>
</div>
Pagination
<ul class="pagination">
<li class="disabled"><a>←</a></li>
<li><a class="active" href="?page=1">1</a></li>
<li><a href="?page=2">2</a></li>
<li><a href="?page=3">3</a></li>
<li><a href="?page=2">→</a></li>
</ul>
Feedback & Status-Komponenten
Spinner
<div class="spinner spinner-sm"></div>
<div class="spinner"></div> <!-- default -->
<div class="spinner spinner-lg"></div>
Fortschrittsbalken
<div class="progress">
<div class="progress-bar" data-progress="75"></div>
</div>
<div class="progress">
<div class="progress-bar success" data-progress="100"></div>
</div>
Skeleton (Lade-Platzhalter)
<div class="skeleton skeleton-line is-short"></div>
<div class="skeleton skeleton-title"></div>
<div class="skeleton skeleton-block"></div>
KPI / Stat
<div class="stat">
<span class="stat-label">Umsatz</span>
<span class="stat-value">€ 48.291</span>
<span class="stat-change up">↑ +12.4%</span>
</div>
<!-- Trend-basierte Einfärbung des Hauptwerts -->
<div class="stat" data-trend="positive">
<span class="stat-label">Saldo</span>
<span class="stat-value">+ € 1.240</span>
</div>
<div class="stat" data-trend="negative">
<span class="stat-label">Saldo</span>
<span class="stat-value">− € 320</span>
</div>
Avatar
<div class="avatar">AM</div>
<div class="avatar avatar-sm">AM</div>
<div class="avatar avatar-lg"><img src="..." alt="Profilbild"></div>
<!-- Avatar Group -->
<div class="avatar-group">
<div class="avatar avatar-sm">AM</div>
<div class="avatar avatar-sm">BS</div>
<div class="avatar avatar-sm">CK</div>
</div>
Empty State
<div class="empty">
<svg class="empty-icon"><!-- Illustration/Icon --></svg>
<p class="empty-title">Keine Einträge</p>
<p class="empty-description">Erstelle deinen ersten Eintrag, um loszulegen.</p>
<button class="btn btn-primary btn-sm">Erstellen</button>
</div>
Toasts
<div class="toast-container" id="toast-container"></div>
<!-- Aus einem Button heraus -->
<button class="btn" data-action="toast" data-message="Gespeichert!" data-type="success">Speichern</button>
<!-- Nach einer HTMX-Antwort: Server setzt HX-Trigger, eigenes Skript (als Datei) reagiert -->
<!-- Response-Header: HX-Trigger: {"toast": {"message": "Gespeichert!", "type": "success"}} -->
<!-- static/js/app.js: document.body.addEventListener('toast', e => showToast(e.detail.message, e.detail.type)); -->
Divider mit Label
<div class="divider">oder</div>
Filter-Leiste
<!-- Flex-Row, auf Mobile gestapelt (< 40rem) -->
<div class="filter-bar">
<div class="form-group">
<label>Monat</label>
<input type="month">
</div>
<div class="form-group">
<label>Typ</label>
<select>
<option>Alle</option>
<option>Einnahme</option>
</select>
</div>
<button class="btn btn-secondary btn-sm">Filtern</button>
</div>