356

How do you definitively detect whether or not the user has pressed the back button in the browser?

How do you enforce the use of an in-page back button inside a single page web application using a #URL system?

Why on earth don't browser back buttons fire their own events!?

Just a coder
  • 15,480
  • 16
  • 85
  • 138
Xarus
  • 6,589
  • 4
  • 15
  • 22
  • 4
    I wish navigation events (backward/forward) get added sometime. So far this is something being in works https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming – Howdy Jun 18 '19 at 16:34
  • Please support this proposal for the `ongoback` event: https://discourse.wicg.io/t/set-back-button-url-in-pwas/4112 – collimarco Jun 10 '21 at 09:03
  • 3
    Is it possible that these buttons don't allow interception since that would allow an app to "lock" the browser on a page? – William T. Mallard Jul 08 '22 at 19:16
  • 300 upvote and not a single working answer yet – greendino Jul 25 '23 at 10:04

21 Answers21

247

(Note: As per Sharky's feedback, I've included code to detect backspaces)

So, I've seen these questions frequently on SO, and have recently run into the issue of controlling back button functionality myself. After a few days of searching for the best solution for my application (Single-Page with Hash Navigation), I've come up with a simple, cross-browser, library-less system for detecting the back button.

Most people recommend using:

window.onhashchange = function() {
 //blah blah blah
}

However, this function will also be called when a user uses on in-page element that changes the location hash. Not the best user experience when your user clicks and the page goes backwards or forwards.

To give you a general outline of my system, I'm filling up an array with previous hashes as my user moves through the interface. It looks something like this:

function updateHistory(curr) {
    window.location.lasthash.push(window.location.hash);
    window.location.hash = curr;
}

Pretty straight forward. I do this to ensure cross-browser support, as well as support for older browsers. Simply pass the new hash to the function, and it'll store it for you and then change the hash (which is then put into the browser's history).

I also utilise an in-page back button that moves the user between pages using the lasthash array. It looks like this:

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

So this will move the user back to the last hash, and remove that last hash from the array (I have no forward button right now).

So. How do I detect whether or not a user has used my in-page back button, or the browser button?

At first I looked at window.onbeforeunload, but to no avail - that is only called if the user is going to change pages. This does not happen in a single-page-application using hash navigation.

So, after some more digging, I saw recommendations for trying to set a flag variable. The issue with this in my case, is that I would try to set it, but as everything is asynchronous, it wouldn't always be set in time for the if statement in the hash change. .onMouseDown wasn't always called in click, and adding it to an onclick wouldn't ever trigger it fast enough.

This is when I started to look at the difference between document, and window. My final solution was to set the flag using document.onmouseover, and disable it using document.onmouseleave.

What happens is that while the user's mouse is inside the document area (read: the rendered page, but excluding the browser frame), my boolean is set to true. As soon as the mouse leaves the document area, the boolean flips to false.

This way, I can change my window.onhashchange to:

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

You'll note the check for #undefined. This is because if there is no history available in my array, it returns undefined. I use this to ask the user if they want to leave using a window.onbeforeunload event.

So, in short, and for people that aren't necessarily using an in-page back button or an array to store the history:

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

And there you have it. a simple, three-part way to detect back button usage vs in-page elements with regards to hash navigation.

EDIT:

To ensure that the user doesn't use backspace to trigger the back event, you can also include the following (Thanks to @thetoolman on this Question):

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});
radbyx
  • 9,352
  • 21
  • 84
  • 127
Xarus
  • 6,589
  • 4
  • 15
  • 22
  • 10
    +1 nice idea, but i think this will fail if user uses whatever keyboard shortcut is for "back" (backspace key on firefox) whilst his mouse is inside browser window – Sharky Sep 12 '14 at 10:56
  • Agreed, but you can intercept the onkey event and check for backspace anyways. The issue has always been detecting the click of the back button. :) – Xarus Sep 12 '14 at 11:00
  • 2
    you should implement this too, its a pity to leave it like this :D – Sharky Sep 12 '14 at 11:01
  • 4
    Will do - I'm in the office right now anyways :) (EDIT: Done now) – Xarus Sep 12 '14 at 11:02
  • 16
    What about mobile (e.g. ipad) – basarat Jan 27 '15 at 03:40
  • 1
    @basarat - I haven't tested on an iPad or other mobile devices - but given how there are no mouse events on touch devices - I don't believe this is mobile friendly - though I'll spend some time looking into a way to adapt it. :) – Xarus Jan 27 '15 at 12:26
  • 8
    What about swipe events from trackpad in MAC. Could that be captured as well? – Sriganesh Navaneethakrishnan Jul 16 '15 at 22:53
  • @SriganeshNavaneethakrishnan - I'll need to look into that as well, but I don't have a trackpad or mac at my disposal. – Xarus Jul 17 '15 at 09:11
  • 6
    How can I differentiate forward and backward buttons? – Mr_Perfect Dec 06 '16 at 05:52
  • 3
    UPDATE: `window.onhashchange` is **not called** in latest Chrome (69) when I click _back_ button. – Tom Oct 17 '18 at 07:28
  • 2
    UPDATE: Tom, it is called in Chrome (72) but ONLY if you arrive at that page/hash from another page/hash (maybe the same in 69?). If you hit reload and then press the back button it is NOT called. The same is true for popstate. If anyone finds a solution to catching the back button immediately after a reload then please let me know. :) – SpaceManGalaxy Feb 22 '19 at 22:57
  • 1
    `document.onmouseleave` does not work in FireFox (ver 69. but did in Safari and Chrome). Nor does `document.addEventListener('mouseleave', ....`. Instead I opted for `document.getElementsByTagName('body')[0].addEventListener('mouseleave', ...` Not as pretty yet does the trick. – davidhartman00 Oct 15 '19 at 21:17
  • @Mr_Perfect See a possible solution here if you want both forward and back buttons: https://stackoverflow.com/questions/57102502/preventing-mouse-fourth-and-fifth-buttons-from-navigating-back-forward-in-browse/62482736#62482736 – CubicleSoft Jun 20 '20 at 07:08
  • Is there a way to tell if user pressed cancel or leave page – Constantine Westerink Apr 20 '21 at 11:50
  • what is the difference to the popstate event and are there even more possible options that are not onpageleave and unload? – LuckyLuke Skywalker Apr 23 '22 at 10:44
142

You can try popstate event handler, e.g:

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

Note: For the best results, you should load this code only on specific pages where you want to implement the logic to avoid any other unexpected issues.

The popstate event is fired each time when the current history entry changes (user navigates to a new state). That happens when user clicks on browser's Back/Forward buttons or when history.back(), history.forward(), history.go() methods are programatically called.

The event.state is property of the event is equal to the history state object.

For jQuery syntax, wrap it around (to add even listener after document is ready):

(function($) {
  // Above code here.
})(jQuery);

See also: window.onpopstate on page load


See also the examples on Single-Page Apps and HTML5 pushState page:

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

This should be compatible with Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ and similar.

Community
  • 1
  • 1
kenorb
  • 155,785
  • 88
  • 678
  • 743
  • 2
    Kenorb, you're correct that popstate works to grab the change, but it doesn't differentiate between programmatically calling the event and when the user clicks the browser's buttons. – Xarus May 09 '16 at 12:08
  • 1
    Great post on [Single-Page Apps and HTML5 pushState](http://zinoui.com/blog/single-page-apps-html5-pushstate). Perfect for modern "one page layouts" or "single page apps". Thank you for the link and your answer! – lowtechsun May 28 '16 at 01:04
  • 1
    e.state seem always undefined in modern browsers – FAjir Nov 15 '17 at 16:10
  • I suggest that you put your code in a snippet so that you can run it directly here. – fourk Jun 15 '18 at 18:42
  • 1
    The popstate event is only triggered by performing a browser action, such as clicking on the back button (or calling history.back() in JavaScript), when navigating between two history entries for the same document. ( https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate ) – pref Aug 31 '21 at 20:24
  • 2
    `popstate` event doesn't fire on Back button push. – Hermann Schwarz Mar 03 '23 at 14:22
31
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

This is the only one solution that worked for me (it's not a onepage website). It's working with Chrome, Firefox and Safari.

cercxtrova
  • 1,555
  • 13
  • 30
  • 6
    window.performance.navigation has been deprecated. Here are the docs https://developer.mozilla.org/en-US/docs/Web/API/Performance/navigation – Howdy Jun 18 '19 at 16:12
  • This worked for me on my .cshtml page. Worked successfully on Chrome and IE. Thanks – Justjyde Apr 25 '20 at 05:34
  • 2
    @llaaalu This works after the deprecation, I'm not sure about cross browser compatibility: if (String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward") { // do your code here } – Mladen Adamovic Oct 25 '20 at 11:37
  • 1
    Oh my gosh! I was trying a lot of variants but only your solution is working!!! Thank you! You save me after 3 hours of working! – Hottabov Sep 06 '22 at 15:00
  • This is the only solution that works!!! `popstate` event (previous solutions) doesn't fire on Back button push. – Hermann Schwarz Mar 03 '23 at 14:24
24

I had been struggling with this requirement for quite a while and took some of the solutions above to implement it. However, I stumbled upon an observation and it seems to work across Chrome, Firefox and Safari browsers + Android and iPhone

On page load:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

Let me know if this helps. If am missing something, I will be happy to understand.

Nelson Yeung
  • 3,262
  • 3
  • 19
  • 29
Itzmeygu
  • 397
  • 3
  • 4
23

In javascript, navigation type 2 means browser's back or forward button clicked and the browser is actually taking content from cache.

if(performance.navigation.type == 2)
{
    //Do your code here
}
Eric
  • 6,563
  • 5
  • 42
  • 66
Hasan Badshah
  • 773
  • 1
  • 6
  • 16
  • 8
    This doesn't work on a single page application, the result is always 1 (which means reload). Moreover it doesn't make the difference between back and forward button, which is very unfortunate. – papillon Dec 21 '18 at 09:55
  • " Moreover it doesn't make the difference between back and forward button, which is very unfortunate. " yes because whenever data is fetched from cache that time the performance.navigation.type is 2 – Hasan Badshah Dec 26 '18 at 13:54
  • That's not guaranteed to work in all browsers! so you should write something like this : if(window.performance){ // your performance related code } also it's better to use TYPE_BACK_FORWARD instead of 2 for more readability. – blank94 Apr 14 '19 at 00:28
  • 3
    ... and this is now deprecated. See: https://developer.mozilla.org/en-US/docs/Web/API/Performance/navigation – Mister Vanderbilt Oct 22 '20 at 14:25
  • @MisterVanderbilt as this is deprecated, what would be the new alternative code. This solution is so simple, would like to use it – Mladen Adamovic Oct 25 '20 at 11:25
  • 1
    This works after the deprecation, I'm not sure about cross browser compatibility: if (String(window.performance.getEntriesByType("navigation")[0].type) === "back_forward") { // do your code here } – Mladen Adamovic Oct 25 '20 at 11:39
  • 3
    I don't care. It works for me, is good! Dec 2020 – Cătălin Rădoi Dec 15 '20 at 08:19
  • 1
    deprecated !! read this for more : https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigation/type – Shurvir Mori Jul 22 '22 at 09:48
22

Correct answer is already there to answer the question. I want to mention new JavaScript API PerformanceNavigationTiming, it's replacing deprecated performance.navigation.

Following code will log in console "back_forward" if user landed on your page using back or forward button. Take a look at compatibility table before using it in your project.

var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
    console.log(perfEntries[i].type);
}
Howdy
  • 557
  • 7
  • 12
  • This is not a way to tell if a back button *is clicked on this page*. It tells if it *was clicked on the last page*. – Seph Reed Dec 31 '19 at 16:53
  • 5
    But it happened to be the actual answer I was looking for since the issue I get is after I hit the back button and not before meaning I can build in some response code that stops my duplicate requests issues. Thanks. – Andrew Mar 08 '20 at 20:32
  • 3
    This may not answer the question, but exactly what I needed! Nice one - I did not know of this... – Hogsmill Jun 18 '20 at 13:42
16

This will definitely work (For detecting back button click)

$(window).on('popstate', function(event) {
 alert("pop");
});
rohan parab
  • 1,589
  • 1
  • 14
  • 18
12

My variant:

const isVisitedViaBackButton = performance && performance.getEntriesByType( 'navigation' ).map( nav => nav.type ).includes( 'back_forward' )
WP Punk
  • 1,344
  • 9
  • 25
7

See this:

history.pushState(null, null, location.href);
    window.onpopstate = function () {
        history.go(1);
    };

it works fine...

Jorge Rocha
  • 778
  • 7
  • 9
6

Browser: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

For mobile control: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>
Limitless isa
  • 3,689
  • 36
  • 28
  • This doesn't answer the question asked. The question is about detecting the use of an in-page back button vs the browser's native back button. – Xarus Nov 01 '16 at 09:53
  • 3
    Question is tagged javascript, not jquery. – skwny Jan 27 '17 at 18:12
5

I was able to use some of the answers in this thread and others to get it working in IE and Chrome/Edge. history.pushState for me wasn't supported in IE11.

if (history.pushState) {
    //Chrome and modern browsers
    history.pushState(null, document.title, location.href);
    window.addEventListener('popstate', function (event) {
        history.pushState(null, document.title, location.href);
    });
}
else {
    //IE
    history.forward();
}
Arsalan Siddiqui
  • 181
  • 2
  • 11
  • 3
    Just tried that on Chrome 78.0.3904.70 (Official Build) (64-bit) and it did not work. – Jeffz Oct 30 '19 at 01:38
4

A full-fledged component can be implemented only if you redefine the API (change the methods of object ' history ') I will share the class just written. Tested on Chrome and Mozilla Support only HTML5 and ECMAScript5-6

class HistoryNavigation {
    static init()
    {
        if(HistoryNavigation.is_init===true){
            return;
        }
        HistoryNavigation.is_init=true;

        let history_stack=[];
        let n=0;
        let  current_state={timestamp:Date.now()+n};
        n++;
        let init_HNState;
        if(history.state!==null){
            current_state=history.state.HNState;
            history_stack=history.state.HNState.history_stack;
            init_HNState=history.state.HNState;
        } else {
            init_HNState={timestamp:current_state.timestamp,history_stack};
        }
        let listenerPushState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):{};
            let h_state={ timestamp:Date.now()+n};
            n++;
            let key = history_stack.indexOf(current_state.timestamp);
            key=key+1;
            history_stack.splice(key);
            history_stack.push(h_state.timestamp);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            current_state=h_state;
            return params;
        };
        let listenerReplaceState=function(params){
            params=Object.assign({state:null},params);
            params.state=params.state!==null?Object.assign({},params.state):null;
            let h_state=Object.assign({},current_state);
            h_state.history_stack=history_stack;
            params.state.HNState=h_state;
            return params;
        };
        let desc=Object.getOwnPropertyDescriptors(History.prototype);
        delete desc.constructor;
        Object.defineProperties(History.prototype,{

            replaceState:Object.assign({},desc.replaceState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.replace',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerReplaceState(params);
                    desc.replaceState.value.call(this,params.state,params.title,params.url);
                }
            }),
            pushState:Object.assign({},desc.pushState,{
                value:function(state,title,url){
                    let params={state,title,url};
                    HistoryNavigation.dispatchEvent('history.state.push',params);
                    params=Object.assign({state,title,url},params);
                    params=listenerPushState(params);
                    return desc.pushState.value.call(this, params.state, params.title, params.url);
                }
            })
        });
        HistoryNavigation.addEventListener('popstate',function(event){
            let HNState;
            if(event.state==null){
                HNState=init_HNState;
            } else {
                HNState=event.state.HNState;
            }
            let key_prev=history_stack.indexOf(current_state.timestamp);
            let key_state=history_stack.indexOf(HNState.timestamp);
            let delta=key_state-key_prev;
            let params={delta,event,state:Object.assign({},event.state)};
            delete params.state.HNState;
            HNState.history_stack=history_stack;
            if(event.state!==null){
                event.state.HNState=HNState;
            }
            current_state=HNState;
            HistoryNavigation.dispatchEvent('history.go',params);
        });

    }
    static addEventListener(...arg)
    {
        window.addEventListener(...arg);
    }
    static removeEventListener(...arg)
    {
        window.removeEventListener(...arg);
    }
    static dispatchEvent(event,params)
    {
        if(!(event instanceof Event)){
            event=new Event(event,{cancelable:true});
        }
        event.params=params;
        window.dispatchEvent(event);
    };
}
HistoryNavigation.init();

// exemple

HistoryNavigation.addEventListener('popstate',function(event){
    console.log('Will not start because they blocked the work');
});
HistoryNavigation.addEventListener('history.go',function(event){
    event.params.event.stopImmediatePropagation();// blocked popstate listeners
    console.log(event.params);
    // back or forward - see event.params.delta

});
HistoryNavigation.addEventListener('history.state.push',function(event){
    console.log(event);
});
HistoryNavigation.addEventListener('history.state.replace',function(event){
    console.log(event);
});
history.pushState({h:'hello'},'','');
history.pushState({h:'hello2'},'','');
history.pushState({h:'hello3'},'','');
history.back();

    ```

AlexeyP0708
  • 307
  • 2
  • 5
  • Nice approach! Thanks for adding to this (I still find it amazing that there's conversation on this thread after so many years) – Xarus Feb 06 '20 at 11:17
  • 3
    This appears to be a clever history tracking mechanism. However, the code is uncommented, so it's pretty difficult to follow. If someone navigates away from the current page, the code won't detect that button press, which doesn't answer the original question of "How do you definitively detect whether or not the user has pressed the back button in the browser?" Button presses and history tracking are two different things even though one may trigger the other. The fact there's still conversation indicates a major flaw in web browser design. – CubicleSoft Apr 27 '20 at 15:48
  • CubicleSoft, Let’s imagine that there is an actual transition (a page formed directly when the link is clicked) and a virtual transition (a page generated by the event, while there is no real click through). In the actual transition, (if the domains are different during the transition), the browser does not allow you to track the transitions due to security policies and privacy. With a dynamic transition, your code is executed in the context of your actions, you have the opportunity to track the actions in the navigation panel. At the very least, this is satisfactory for your SPA application. – AlexeyP0708 Jul 10 '20 at 16:08
3

Here's my take at it. The assumption is, when the URL changes but there has no click within the document detected, it's a browser back (yes, or forward). A users click is reset after 2 seconds to make this work on pages that load content via Ajax:

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);
TomTom101
  • 6,581
  • 2
  • 20
  • 31
1

The document.mouseover does not work for IE and FireFox. However I have tried this :

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

This works for Chrome and IE and not FireFox. Still working to get FireFox right. Any easy way on detecting Browser back/forward button click are welcome, not particularly in JQuery but also AngularJS or plain Javascript.

0

I solved it by keeping track of the original event that triggered the hashchange (be it a swipe, a click or a wheel), so that the event wouldn't be mistaken for a simple landing-on-page, and using an additional flag in each of my event bindings. The browser won't set the flag again to false when hitting the back button:

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}
0
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });

The above code worked for me. On mobile browsers, when the user clicked on the back button, we wanted to restore the page state as per his previous visit.

Mihai Chelaru
  • 7,614
  • 14
  • 45
  • 51
Ashwin
  • 9
  • 3
  • Above code worked for me , on mobile browsers, when users clicked on back button , we wanted to restore the page state as per his previous visit – Ashwin Jul 17 '18 at 19:25
  • There's no reason to store the state in the DOM. Nor should you be requerying the DOM for the input and it should be stored as a local variable. If you don't want an `` to be displayed, use ``. If you wanted to use this approach, a variable on the `window` would be preferred, but even that isn't wise. – toastal Nov 25 '20 at 07:54
0

Solution for Kotlin/JS (React):

import org.w3c.dom.events.Event
import kotlin.browser.document
import kotlin.browser.window

...
override fun componentDidMount() {
    window.history.pushState(null, document.title, window.location.href)
    window.addEventListener("popstate", actionHandler)
}
...
val actionHandler: (Event?) -> Unit = {
    window.history.pushState(
        null,
        document.title,
        window.location.href
    )
    // add your actions here
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
alexrnov
  • 2,346
  • 3
  • 18
  • 34
0

Was looking for a solution for this issue and put together a simple skeleton test html based on a few answers here and the MDN Web Doc pages for History.pushState() and WindowEventHandlers.onpopstate.

The following HTML and JavaScript is easy enough to copy and paste and test.

Works with back and forward browser buttons, shortcut keys, adds a change to the URL (which is important in some cases).

Simply enough to add to existing code key points and should be expandable too.

<html>
<body>
<div id="p1">Option 1</div>
<div id="p2">Option 2</div>
<div id="p3">Option 3</div>
<div id="p4">Option 4</div>
<div id="c"></div>
<script>
var chg={
    set:function(str){
        var d=document.getElementById("c");
        d.textContent=str;
    },
    go:function(e){
        var s={"p":this.id};
        chg.set(s.p);
        hstry.add(s);
    }
};
var hstry={
    add:function(s){
        var u=new URL(window.location);
        u.searchParams.set("x",s.p);
        window.history.pushState(s,"",u);
    },
    adjust:function(state){
        if(state.p){
            chg.set(state.p);
        }
    }
};
window.onpopstate=function(e){
    console.log("popstate, e.state:["+ JSON.stringify(e.state) +"]");
    hstry.adjust(e.state);
}
window.onload=function(){
    var i,d,a=["p1","p2","p3","p4"];
    for(i=0;i<a.length;i++){
        d=document.getElementById(a[i]);
        d.addEventListener("click",chg.go,false);
    }
}
</script>
</body>
</html>
Tigger
  • 8,980
  • 5
  • 36
  • 40
0

browser will emit popstate event if you navigate through your app with calling

window.history.pushState({},'','/to')

If you manually enter the addresses into the address bar and click on the back button, popstate event will NOT be fired.

If you navigate in your app with this simplified function

const navigate = (to) => {
    window.history.pushState({}, ",", to);
  };

then this will work

const handlePopstate = () => {
  console.log("popped");
};
window.addEventListener("popstate", handlePopstate);
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
0

Here is my implementation of a sidemenu that can be closed using the back button. Works on Chrome/Edge/Android/...

<html>

<head>
<style>
    .sidebarMenu {
        height: 25%;
        position: fixed;
        left: 0;
        width: 25%;
        margin-top: 20px;
        transform: translateX(-100%);
        transition: transform 250ms ease-in-out;
        background-color: #aaa;
        opacity: 1;
    }

    .openSidebarMenu {
        transition: all 0.3s;
        box-sizing: border-box;
        display: none;
    }

    .openSidebarMenu:checked ~ #sidebarMenu {
        transform: translateX(0);
    }
</style>
</head>

<body>
<input type="checkbox" class="openSidebarMenu" id="openSidebarMenu" onclick="sidemenu()">
<label for="openSidebarMenu">
Menu (click me or back button to close)
</label>
<div id="sidebarMenu" class="sidebarMenu" onclick="sideBarClose()">
    <ul class="sidebarMenuInner">
        <li>Menu 1</li>
        <li>Menu 2</li>
    </ul>
</div>

<script>
    function sidemenu() {
        var selection = document.getElementById("openSidebarMenu");
        if (selection.checked) {
            window.history.pushState({page: 1}, "", "");
            checked = true;
            window.onpopstate = function(event) {
                var selection = document.getElementById("openSidebarMenu");
                if(event && selection.checked) {
                    selection.checked = false;
                    console.log("event 1");

                } else {
                    console.log("event 2");
                }
            }
        } else {
            history.back();
        }
    }
    
    function sideBarClose() {
        var selection = document.getElementById("openSidebarMenu");
        if (selection.checked) {
            selection.checked = false;
            history.back();
        }
    }   
</script>

</body>
</html>
XPloRR
  • 342
  • 3
  • 8
-38

I tried the above options but none of them is working for me. Here is the solution

if(window.event)
   {
        if(window.event.clientX < 40 && window.event.clientY < 0)
        {
            alert("Browser back button is clicked...");
        }
        else
        {
            alert("Browser refresh button is clicked...");
        }
    }

Refer this link http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli for more details

  • 14
    @MunamYousuf It's pretty obvious why this piece of code doesn't really work. It tracks the back button of the browser but the button is outside the viewport, hence the coordinates clientX and clientY should not be obtainable. Assuming it works, how about iOS? The back button is at the bottom... Also the way it is written is super inefficient, it is a conditional for every single event triggered... God it's so bad that am going to give it a down vote. – James Wong Aug 08 '17 at 03:42
  • 2
    This is horrendous! why would you do such thing? :/ and it won't even work as James said. – msqar Feb 21 '18 at 17:47
  • this is funny AF, tho XD – Eduardo La Hoz Miranda Jan 14 '22 at 18:07