Zum Hauptinhalt springen
Version: latest

Einstellungsseiten-Muster

Einstellungsseiten kombinieren Formularvalidierung, Abschnittsgliederung und Speicher-Feedback. Dieses Muster erstellt einen vollständigen Einstellungsbildschirm mit Tab-basierter Navigation zwischen Abschnitten, Inline-Validierung und Toast-Benachrichtigung beim Speichern.


Wann dieses Muster verwenden

  • Konto-, Profil-, Benachrichtigungs- und Abrechnungseinstellungen
  • Formulare mit vielen Feldern, die in logische Abschnitte unterteilt sind
  • Wenn dauerhaftes Speicher-Feedback ohne Blockierung der UI gezeigt werden soll

Komponenten-Setup

app/settings/page.tsx
import { Tabs } from "@prokodo/ui/tabs"
import "@prokodo/ui/tabs.css"
import { ProfileSection } from "./ProfileSection"
import { NotificationsSection } from "./NotificationsSection"

const tabs = [
{ value: "profile", label: "Profil", content: <ProfileSection /> },
{
value: "notifications",
label: "Benachrichtigungen",
content: <NotificationsSection />,
},
{ value: "security", label: "Sicherheit", content: <SecuritySection /> },
]

export default function SettingsPage() {
return (
<main style={{ maxWidth: "720px", margin: "0 auto", padding: "2rem" }}>
<h1>Einstellungen</h1>
<Tabs
id="settings-tabs"
ariaLabel="Einstellungsbereiche"
items={tabs}
defaultValue="profile"
/>
</main>
)
}

Profil-Formular

app/settings/ProfileSection.tsx
"use client"

import { useState } from "react"
import { Input } from "@prokodo/ui/input/client"
import { Select } from "@prokodo/ui/select/client"
import { Snackbar } from "@prokodo/ui/snackbar/client"
import { Button } from "@prokodo/ui/button/client"
import "@prokodo/ui/input.css"
import "@prokodo/ui/select.css"
import "@prokodo/ui/snackbar.css"
import "@prokodo/ui/button.css"

export function ProfileSection() {
const [saved, setSaved] = useState(false)

async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const data = new FormData(e.currentTarget)
await updateProfile({
name: data.get("name") as string,
timezone: data.get("timezone") as string,
})
setSaved(true)
setTimeout(() => setSaved(false), 3000)
}

return (
<>
<form onSubmit={handleSubmit} style={{ display: "grid", gap: "1rem" }}>
<Input
name="name"
label="Anzeigename"
required
minLength={2}
autoComplete="name"
/>
<Select
id="timezone-select"
name="timezone"
label="Zeitzone"
items={[
{ value: "UTC", label: "UTC" },
{ value: "Europe/Berlin", label: "Europe/Berlin" },
{ value: "America/New_York", label: "America/New_York" },
]}
defaultValue="Europe/Berlin"
onChange={(_e, _v) => {}}
/>
<Button
title="Änderungen speichern"
type="submit"
variant="contained"
color="primary"
/>
</form>

<Snackbar
message="Einstellungen gespeichert"
color="success"
open={saved}
autoHideDuration={3000}
onClose={() => setSaved(false)}
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
/>
</>
)
}

Formularvalidierung

Form führt native Constraint-Validierung durch, bevor action aufgerufen wird. Für asynchrone Servervalidierung useActionState (React 19) verwenden:

import { useActionState } from "react"

const [state, action, isPending] = useActionState(updateProfile, undefined)

<Input name="name" label="Anzeigename" errorText={state?.errors?.name} />

Barrierefreiheit

  • Jeder Formularabschnitt sollte in ein <section> mit einem visuell versteckten <h2> eingebettet sein.
  • Snackbar verwendet standardmäßig role="status" und aria-live="polite".

Verwandte Komponenten

  • Form — Server-Action-kompatibel, Constraint-Validierung
  • Input — Label, Hint, Fehler- und Pflichtfeld-Zustände
  • Select — Einzel- und Mehrfachauswahl-Varianten
  • Snackbar — Toast-Nachrichten mit Varianten
  • Tabs — tastaturzugängliche Tab-Navigation

Weiterführende Informationen


👉 Einstellungsseite in Storybook öffnen