Context
A contact form should feel lightweight and calm, but behave like a real product UI: predictable states, clear feedback, and accessibility.
Decisions
- Global status + field-level errors
Provide a summary message and point to the exact fields. - Correct aria-live behavior
Use polite updates for info and assertive updates for errors. - Keep the form visible after success
Dim or “soft-collapse” fields instead of hiding the entire form.
Implementation notes
- Use an in-flight guard to prevent double submits.
- Clear field errors on input changes.
- Reset Turnstile on relevant error paths to avoid stale tokens.
Lessons learned
Good UX is a combination of behavior, wording, and a11y — not just styling.
Links
- Live: https://michelnauen.dev/contact
- Repo: (private)