| type |
status |
owner |
last_update |
related |
| Frontend Guideline |
APPROVED |
đïž UI/UX Designer |
2026-04-03 |
| docs/06_Frontend/Guidelines/Editier-Formulare_Dialog-vs-Fullscreen_v1.md |
| docs/04_Agents/Roadmaps/UIUX_Roadmap.md |
| docs/04_Agents/Roadmaps/Frontend_Roadmap.md |
|
Empty States â Design-Spezifikation & Richtlinie
Ziel: Konsistente, hilfreiche Leer-ZustĂ€nde fĂŒr alle Listenansichten im Meldestelle-Desktop.
Leitsatz: Ein leerer Zustand ist kein Fehler â er ist eine Einladung zur ersten Aktion.
1. Warum Empty States wichtig sind
- Erster Start / Onboarding: Neue Nutzer sehen leere Listen â ohne Hinweis wirkt die App kaputt.
- Nach Filterung: Kein Treffer bei Suche/Filter muss klar kommuniziert werden (â Ladefehler).
- Nach Löschung: Letzte EntitĂ€t gelöscht â leere Liste braucht Orientierung.
- Vertrauen: Klare Kommunikation verhindert Unsicherheit ("Ist das ein Bug?").
2. Empty-State-Typen
| Typ |
Auslöser |
PrimÀre Aktion |
EMPTY_LIST |
Liste ist leer (noch keine Daten angelegt) |
CTA: Ersten Eintrag anlegen |
NO_RESULTS |
Suche/Filter liefert keine Treffer |
CTA: Filter zurĂŒcksetzen |
ERROR |
Ladefehler (Netzwerk, Backend nicht erreichbar) |
CTA: Erneut versuchen |
LOADING |
Daten werden geladen (Skeleton/Spinner) |
Kein CTA |
LOADING wird durch MsLoadingIndicator abgedeckt â kein separater Empty State nötig.
3. Visuelle Anatomie â MsEmptyState
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â â
â [ Icon / 48dp ] â
â â
â Titel (MaterialTheme.titleMedium) â
â â
â Beschreibung (MaterialTheme.bodyMedium, zentriert, â
â max. 2 Zeilen, gedimmt: onSurface 60%) â
â â
â [ PrimĂ€rer CTA-Button ] (optional) â
â â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
MaĂe & AbstĂ€nde
| Element |
Wert |
| Icon-GröĂe |
48 dp |
| Icon-Farbe |
MaterialTheme.colorScheme.onSurface @ 38% Alpha |
| Abstand IconâTitel |
16 dp |
| Abstand TitelâBeschreibung |
8 dp |
| Abstand BeschreibungâButton |
24 dp |
| Max. Breite Textblock |
360 dp (zentriert) |
| Padding gesamt |
32 dp rundum |
Typografie
| Element |
Style |
| Titel |
MaterialTheme.typography.titleMedium |
| Beschreibung |
MaterialTheme.typography.bodyMedium, Alpha 60% |
| Button |
Standard MsButton (outlined fĂŒr sekundĂ€re Aktionen) |
4. Icon-Konzept
Wir verwenden Material Symbols (Outlined) â konsistent mit dem restlichen Design-System.
Kein Custom-Illustration-Set fĂŒr MVP (zu aufwĂ€ndig, zu wenig Mehrwert bei High-Density-Desktop).
| Screen / Kontext |
Icon |
BegrĂŒndung |
| Veranstalter-Liste |
person_off |
Kein Veranstalter vorhanden |
| Veranstaltungs-Liste |
event_busy |
Keine Veranstaltung |
| Turnier-Liste |
emoji_events (durchgestrichen) |
Kein Turnier |
| Bewerb-Liste |
list_alt |
Keine Bewerbe |
| Nennungs-Liste |
assignment_ind |
Keine Nennungen |
| Reiter-Liste |
person_search |
Kein Reiter gefunden |
| Pferde-Liste |
search_off |
Kein Pferd gefunden |
| Verein-Liste |
group_off |
Kein Verein |
| FunktionÀr-Liste |
badge |
Kein FunktionÀr |
| Abteilungs-Startliste |
format_list_numbered |
Keine Starter |
| Abteilungs-Ergebnisliste |
leaderboard |
Keine Ergebnisse |
| Suche / Filter (allg.) |
search_off |
Kein Treffer |
| Fehler (allg.) |
cloud_off |
Verbindungsfehler |
5. Texte je Screen
Allgemeine Regel
- Titel: Kurz, prÀzise, max. 5 Wörter. Keine Ausrufezeichen.
- Beschreibung: ErklÀrt den Zustand UND gibt Handlungshinweis. Max. 2 SÀtze.
- CTA: Verb + Objekt. Klar und direkt.
Texte je Kontext
Veranstalter
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Veranstalter |
Lege den ersten Veranstalter an, um loszulegen. |
Veranstalter anlegen |
NO_RESULTS |
Kein Veranstalter gefunden |
Kein Eintrag passt zur Suche. Passe den Suchbegriff an. |
Suche zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Veranstalter konnten nicht geladen werden. |
Erneut versuchen |
Veranstaltungen
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch keine Veranstaltung |
Erstelle die erste Veranstaltung fĂŒr diesen Veranstalter. |
Veranstaltung anlegen |
NO_RESULTS |
Keine Veranstaltung gefunden |
Kein Treffer fĂŒr den gewĂ€hlten Filter. |
Filter zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Veranstaltungen konnten nicht geladen werden. |
Erneut versuchen |
Turniere
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Turnier |
FĂŒge das erste Turnier zu dieser Veranstaltung hinzu. |
Turnier anlegen |
NO_RESULTS |
Kein Turnier gefunden |
Kein Turnier entspricht dem aktuellen Filter. |
Filter zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Turniere konnten nicht geladen werden. |
Erneut versuchen |
Bewerbe
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Bewerb |
Lege den ersten Bewerb fĂŒr dieses Turnier an. |
Bewerb anlegen |
NO_RESULTS |
Kein Bewerb gefunden |
Kein Bewerb entspricht dem aktuellen Filter. |
Filter zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Bewerbe konnten nicht geladen werden. |
Erneut versuchen |
Nennungen
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch keine Nennung |
Es wurden noch keine Nennungen fĂŒr diesen Bewerb erfasst. |
Nennung erfassen |
NO_RESULTS |
Keine Nennung gefunden |
Kein Treffer fĂŒr den gewĂ€hlten Filter oder die Suche. |
Filter zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Nennungen konnten nicht geladen werden. |
Erneut versuchen |
Reiter
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Reiter |
Importiere Stammdaten oder lege den ersten Reiter an. |
Reiter anlegen |
NO_RESULTS |
Kein Reiter gefunden |
Kein Reiter entspricht dem Suchbegriff. |
Suche zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Reiter konnten nicht geladen werden. |
Erneut versuchen |
Pferde
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Pferd |
Importiere Stammdaten oder lege das erste Pferd an. |
Pferd anlegen |
NO_RESULTS |
Kein Pferd gefunden |
Kein Pferd entspricht dem Suchbegriff. |
Suche zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Pferde konnten nicht geladen werden. |
Erneut versuchen |
Vereine
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein Verein |
Lege den ersten Verein an. |
Verein anlegen |
NO_RESULTS |
Kein Verein gefunden |
Kein Verein entspricht dem Suchbegriff. |
Suche zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
Vereine konnten nicht geladen werden. |
Erneut versuchen |
FunktionÀre
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Noch kein FunktionÀr |
Lege den ersten FunktionÀr an. |
FunktionÀr anlegen |
NO_RESULTS |
Kein FunktionÀr gefunden |
Kein FunktionÀr entspricht dem Suchbegriff. |
Suche zurĂŒcksetzen |
ERROR |
Laden fehlgeschlagen |
FunktionÀre konnten nicht geladen werden. |
Erneut versuchen |
Abteilungs-Startliste
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Keine Starter |
FĂŒr diese Abteilung wurden noch keine Starter zugewiesen. |
Nennungen prĂŒfen |
ERROR |
Laden fehlgeschlagen |
Startliste konnte nicht geladen werden. |
Erneut versuchen |
Abteilungs-Ergebnisliste
| Typ |
Titel |
Beschreibung |
CTA |
EMPTY_LIST |
Keine Ergebnisse |
FĂŒr diese Abteilung wurden noch keine Ergebnisse erfasst. |
â |
ERROR |
Laden fehlgeschlagen |
Ergebnisliste konnte nicht geladen werden. |
Erneut versuchen |
6. Composable-Spezifikation â MsEmptyState
Ablageort:
frontend/core/design-system/src/commonMain/kotlin/at/mocode/frontend/core/designsystem/components/MsEmptyState.kt
API
/**
* Einheitlicher Empty-State fĂŒr alle Listenansichten.
*
* @param icon Material-Symbol (ImageVector) passend zum Kontext.
* @param title Kurzer Titel (max. 5 Wörter).
* @param description ErklÀrung + Handlungshinweis (max. 2 SÀtze). Optional.
* @param actionLabel Text des primÀren CTA-Buttons. Null = kein Button.
* @param onAction Callback fĂŒr den CTA-Button.
* @param modifier Modifier fĂŒr Ă€uĂeres Layout.
*/
@Composable
fun MsEmptyState(
icon: ImageVector,
title: String,
description: String? = null,
actionLabel: String? = null,
onAction: (() -> Unit)? = null,
modifier: Modifier = Modifier
)
Verhalten
- Zentriert (horizontal + vertikal) im verfĂŒgbaren Raum.
- Icon gedimmt (38% Alpha), Beschreibung gedimmt (60% Alpha).
- Button nur anzeigen wenn
actionLabel != null && onAction != null.
- Button-Stil:
OutlinedButton (sekundÀre Aktion, nicht zu dominant).
- Bei
ERROR-Typ: Icon cloud_off, Button als FilledButton (Retry ist primÀre Aktion).
Verwendungsbeispiel
// In einer LazyColumn / Column wenn items.isEmpty():
if (state.reiter.isEmpty() && !state.isLoading) {
MsEmptyState(
icon = Icons.Outlined.PersonSearch,
title = "Noch kein Reiter",
description = "Importiere Stammdaten oder lege den ersten Reiter an.",
actionLabel = "Reiter anlegen",
onAction = { onIntent(ReiterIntent.OpenCreateDialog) }
)
}
7. Implementierungs-Reihenfolge (Sprint C-1)
| PrioritÀt |
Screen |
Typ(en) |
| 1 |
Veranstalter-Auswahl |
EMPTY_LIST, NO_RESULTS |
| 2 |
Veranstaltungs-Ăbersicht |
EMPTY_LIST, NO_RESULTS |
| 3 |
Turnier-Bewerbe-Tab |
EMPTY_LIST |
| 4 |
Turnier-Nennungen-Tab |
EMPTY_LIST, NO_RESULTS |
| 5 |
Reiter-Liste |
EMPTY_LIST, NO_RESULTS |
| 6 |
Pferde-Liste |
EMPTY_LIST, NO_RESULTS |
| 7 |
Verein-Liste |
EMPTY_LIST, NO_RESULTS |
| 8 |
FunktionÀr-Liste |
EMPTY_LIST, NO_RESULTS |
| 9 |
Abteilungs-Startliste |
EMPTY_LIST |
| 10 |
Abteilungs-Ergebnisliste |
EMPTY_LIST |
| Alle |
Alle Listen |
ERROR (einheitlich) |
Hinweis: ERROR-State wird einmalig als Default-Variante in MsEmptyState implementiert
und kann ĂŒberall mit type = EmptyStateType.ERROR aufgerufen werden.
8. Abgrenzung zu anderen Komponenten
| Situation |
Komponente |
| Daten werden geladen |
MsLoadingIndicator |
| Liste leer / kein Treffer |
MsEmptyState |
| Kritischer Fehler (App-Ebene) |
Eigener Error-Screen |
| Inline-Validierungsfehler |
MsValidationWrapper |
| Status einer EntitÀt |
MsStatusBadge |