4

When a modal popup dialog is opened, even if I add a close button (usually a X on top right), some users on mobile will use their mobile "Back button" to close the popup. But instead this will quit the site!

How to make the mobile "Back button" close the popup instead of exiting the website?

document.getElementById("link").onclick = function(e) {
  e.preventDefault();
  document.getElementById("popupdarkbg").style.display = "block";
  document.getElementById("popup").style.display = "block";
    document.getElementById('popupdarkbg').onclick = function() {
      document.getElementById("popup").style.display = "none";
      document.getElementById("popupdarkbg").style.display = "none";
  };
  return false;
}
#popup { display: none; position: fixed; top: 12%; left: 15%; width: 70%; height: 70%; background-color: white; z-index: 10; }
#popupdarkbg { position: fixed; z-index: 5; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; background-color: rgba(0,0,0,.75); display: none; }
<div id="main">
<a href="" id="link">Click me</a><br>
</div>
<div id="popup">This is a popup window! Click mobile "Back button"</div>
<div id="popupdarkbg"></div>

Notes:

  • I've already seen this Codepen How to disable browser back button using JavaScript, but I'm not sure it it's cross-browser on Chrome, Firefox, Safari and on Android, iOS, etc.

  • I've already seen answers about window.onpopstate = function () { history.go(1); }; but I want to make sure this is the good practice to do it here, (so it's not a duplicate of them).

Basj
  • 41,386
  • 99
  • 383
  • 673
  • `pushState` is very well supported across various browsers and platforms, and this approach is a common practice. Unless you're specifically targeting IE9 or lower, you'll be fine. – Máté Safranka Apr 21 '18 at 09:45
  • @MátéSafranka so would you do `window.onpopstate = function () { history.go(1); };` only when popup is open and `window.onpopstate = function () { };` (or something else?) when the popup is closed so that, when the popup is closed, they can still go back to previous site? – Basj Apr 21 '18 at 09:48

2 Answers2

3

Here's a rough version of how I do it in my apps:

var showModal = function() {
    // some code here to show the HTML elements...

    window.history.pushState('backPressed', null, null);
    window.history.pushState('dummy', null, null);
    window.addEventListener('popstate', hideModal, { once: true });
};

var hideModal = function(event) {
    if (event.state == 'backPressed') {
        // hide the HTML elements
    }
};

The reason I add two dummy states is because the popstate event also fires when the URL hash changes, e.g. when the user overwrites the hash manually in the address bar. Checking if the current history state matches backPressed lets me verify that the event was indeed triggered by the Back button.

Máté Safranka
  • 4,081
  • 1
  • 10
  • 22
  • Thank you very much. It works now when using it in Chrome for Android for example, but not when doing it from an app (my app is just an Android WebView displaying the website: the Back button quits the app). – Basj Apr 21 '18 at 10:20
  • Ahhh, well I'm afraid I can't help you with much certainty there. From what little I remember from Android dev, you'll probably need to capture the Back event in the Android app itself, and then use the WebView object's API to somehow notify the JS code on the inside. My guess (looking at the Android reference for WebView) would be to call `goBack()` to simulate the browser's Back button. – Máté Safranka Apr 21 '18 at 10:31
  • 1
    Thanks a lot again! Nota: the Android WebView part has been solved directly [by this answer](https://stackoverflow.com/a/6077173/1422096). – Basj Apr 22 '18 at 20:37
  • @MátéSafranka I guess you have to pop the state if the user dismisses the modal via UI? – Nuthinking Sep 23 '22 at 07:42
0

Here is a minor variation of the accepted answer (*), that I'm finally using:

window.history.pushState('popupclosed', null, null);    // initial state: closed

var hideModal = function(event) {
    if (event.state == 'popupclosed') {
        closepopup();
    }
};

var showModal = function(event) {
    if (history.state !== 'opened') {
        window.history.pushState('opened', null, null);
    }
    window.addEventListener('popstate', hideModal, { once: true });   

The difference with (*) is that here:

  • we only add 1 new state per popup opening in the browser history, instead of 2

  • in the case the previous popup was closed with the X top-right button of the popup (but not using "Previous in history" browser button or "Back button" on phone), then when opening a second popup, don't recreate a new history state opened because it's already the current state.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • This answer seems to work fine. – chillywilly Jul 28 '22 at 05:46
  • Why do you use `history.state` in the condition and `window.history` in the statement below? Is this on purpose or because of differences between `history` and `window.history`? – Esger Feb 23 '23 at 15:17
  • 1
    @Esger If I remember correctly it's the same, but for clarity I should put `window.history` everywhere. – Basj Feb 24 '23 at 08:59