leave warnings for unsaved changes

User Scenario:

  • As a user who edits xyz properties, when I leave the page then I should see a warning prompt to leave and lose changes or stop leaving and remain. 

This is a typical scenario and the approach to handle has not changed in a long time. So lets review it.

But first what are some of the ways a user could "leave" the page

  1. reload the page
  2. browser back button
  3. navigation action to a different url than this app 
  4. edit url in the address bar and hit enter
  5. close the tab
  6. close the browser
  7. navigation action to a different url within this app
  8. close app modal with edits & unsaved changes
  9. considering mobile it gets more complicated because there are other lifecycle events. On Android and iOS mobile apps can be started and stopped as needed by the OS, which is not something web has historically had to deal with. Web has typically just had to deal with user initiated events
Choices 1-6 are all similar: unloading the web page/single page app and are commonly handled using window beforeunload event 
  • mdn note: "Especially on mobile, the beforeunload event is not reliably fired." - e.g. on mobile user visits page but switches to another app and late OS closes the page (see more on new dom events such as visibilitychanged)

Choice 7 & 8 represents actions which don't reload the page, such as a navigation event within a single page app. These will not fire the window beforeunload event and need to be handled differently.

To avail of beforeunload, you typically add a listener to window "beforeunload" event and in the callback call preventDefault on the event passed and set returnValue on the event to a string or similar and return that. 
Don't forget to remove the listener when finished.
  • typically calling preventDefault and setting returnValue is only done if there are unsaved changes on the page (so you need some way to know if changes have happend and when they are reset such as when saved)
  • when you do stop the default action then the browser will automatically show a prompt to stay or leave
    • you have no control over this prompt, styling or message content, and it looks different across browsers
  • not enough to call preventDefault, you have to also set event returnValue and return it; in older browsers the value in returnValue was displayed but not any more in more modern browsers
  • as mentioned, advice on usage is evolving, one of chromes recommendation is to use beforeunload with caution and never add beforeunload listener unconditionally. Instead, add it when there are unsaved changes and remove it once changes are saved

We're using the latest version of react-router v6.8 and a data router and they (finally) added some support for handling this scenario with their new useBeforeUnload() hook. But honestly it's very basic and just a wrapper around window beforeunload (disappointed). I tracked a long thread about why it was left out, then finally added back and I know the react-router team didn't want to add it back due to various complexities etc. but the community wanted it. What they implemented reflects their reluctance imo. It also adds the listener unconditionally and does not provide the fine grained control to add and remove as Chrome recommends (see above).

There are new lifecycle events being added to support mobile and more sophisticated resource management even on web. This is a good post on the topic from chrome. New dom events such as visibilitychange and freeze provide new ways to respond to changes in app state. But for our needs and user base, for now we will continue to use beforeunload for the basic case of warning of unsaved changes.

Re new events, transitioning to hidden state (visibilitychange event) is considered likely to end a users session and is the recommended event to key off to: 1. persist unsaved application state 2. send any analytics and 3. stop any background tasks. Freeze dom event is another trigger to stop using resources (important in a mobile context).
But beforeunload is still the appropriate event to use to warn & prompt a user of unsaved changes when unloading the page (with prior cavet about when to add and remove listeners).
 

references
https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
https://developer.chrome.com/blog/page-lifecycle-api/
Older 2015, but interesting: https://www.igvita.com/2015/11/20/dont-lose-user-and-app-state-use-page-visibility/

Safari Leave warning (same as Reload warning) built in prompts

Edge Reload and Leave built in prompts

Chrome Reload and Leave













Comments

Popular posts from this blog

deep dive into Material UI TextField built by mui

angular js protractor e2e cheatsheet

react-router v6.4+ loaders, actions, forms and more