2.5 KiB
2.5 KiB
Contract: Modal Workflows
Version: 1.0
State Machine
Every modal has exactly these states:
closed → open → submitting → success | error
↓
cancel → closed
open: form visible, submit enabled.submitting: form disabled, spinner on submit button, no double-submit possible.success: close modal, show toast, refresh affected data.error: stay open, show error message inline, re-enable form.cancel: close without changes, no confirmation needed unless form is dirty.
Rules
- Destructive actions (delete, archive, bulk remove) require a separate confirmation modal — not just a disabled button. Confirmation modal must name the target: "Delete component ABC-123?"
- Never close a modal automatically on error — keep it open so the user can retry or copy the error.
- Submit button text must describe the action: "Save", "Delete", "Archive" — not "OK" or "Confirm".
- Modal title must match the action: "Edit Component", "Delete Asset" — not generic "Modal".
- Escape key and clicking the backdrop close the modal (unless in
submittingstate).
Validation
- Validate on submit server-side. Client-side validation is optional progressive enhancement only.
- Show field-level errors inline below each field.
- Show a form-level error summary at the top if multiple fields fail.
- Error messages must be human-readable and action-oriented: "Serial number is required" — not "serial_number: cannot be null".
htmx Pattern (server-rendered modals)
POST /api/entity → 200 OK + HX-Trigger: "entitySaved" (success)
→ 422 Unprocessable + partial HTML (validation error, re-render form)
→ 500 + error message (server error)
- On success: server sends
HX-Triggerheader, JS listener closes modal and refreshes list. - On validation error: server re-renders the form partial with inline errors (422).
- On server error: show generic error toast, log full error server-side.
- Do not use
200 OKfor validation errors — use422so htmx can differentiate.
Multi-Step Modals
Use only when the workflow genuinely requires staged input (e.g. import preview → confirm).
- Show a step indicator (Step 1 of 3).
- Back button must restore previous step values.
- Final confirm step must summarise what will happen before the destructive/irreversible action.
- Single-step edits must NOT be split into multi-step without good reason.