Do not let “saved” cover four different states
| State | Honest interface message | Durable location |
|---|---|---|
| Clean | Saved at 09:30 | Named server or draft store |
| Dirty | Unsaved edits exist in this tab | Browser memory only |
| Saving | Saving draft | Request in flight |
| Saved | Draft saved at 09:34 | Confirmed durable store |
| Failed | Draft not saved; edits remain in this tab | Browser memory only |
| Recovered | Restored from draft saved at 09:32 | Named recovery store |
Avoid “All changes saved” until the durable system has accepted the version the user sees. An autosave timer firing is not a successful save. Local recovery can be valuable, but it should not be described as server persistence and may be inappropriate for sensitive data.
Warn only while work is actually at risk
MDN documents beforeunload as a common way to ask before closing, refreshing,
or navigating away from a page with unsaved data. Its current
beforeunload guidance
also says the event is not reliably fired in some mobile lifecycle paths and can
affect the back-forward cache. Attach it only when dirty edits exist and remove
it after a confirmed save or reset.
The browser controls the warning language in modern implementations. Do not design a custom sentence that the browser cannot display. In-app navigation can use a product-specific review, but the choices still need to match reality: save draft, discard changes, or continue editing.
Add recovery separately from the warning
For work that is costly to recreate, consider a recoverable draft. Define:
- which fields are stored;
- whether the storage is local or server-side;
- when and how it is written;
- how drafts are encrypted and access-controlled where required;
- when they expire;
- how conflicts with a newer canonical record are handled; and
- how the user can discard the recovery copy.
MDN's Page Visibility API provides a signal when a document becomes hidden. It can support a save attempt, but a lifecycle signal is not proof that a network request completed. Frequent or incremental draft persistence is more defensible than relying on one final event at tab close.
Keep failure visible and recoverable
When saving fails, retain the user's input in the current view, announce the failure, and offer retry or copy. Do not clear the form, navigate to a read view, or change the timestamp to imply success. If the session has expired, explain whether reauthentication preserves the draft before sending the user away.
W3C status-message guidance covers success, waiting, and error updates presented without moving focus. A status region can expose those changes programmatically, but the message still needs specific content: what saved, where, and when.
For important data changes, W3C error-prevention guidance supports reversibility, checking, or confirmation. An edit screen can meet that goal with version history, review before final submission, or a recoverable draft—depending on the actual consequence.
Acceptance checks
- The screen distinguishes clean, dirty, saving, saved, failed, and recovered.
- “Saved” follows a durable success response for the current version.
- Dirty state appears after the first meaningful edit, not merely focus.
- A leave warning is present only while unsaved work is at risk.
- The design does not rely on
beforeunloadas its only recovery path. - Save failure preserves visible input and offers a safe next action.
- Recovered content names its source and timestamp before replacing newer work.
- Session expiry, permission loss, and version conflict have explicit outcomes.
- Sensitive fields are not copied into local recovery by default.
This contract does not select a storage system or sync protocol. It makes the durability promise visible enough for product, frontend, backend, security, and accessibility reviewers to test the same behavior.