387

I need to warn users about unsaved changes before they leave a page (a pretty common problem).

window.onbeforeunload = handler

This works but it raises a default dialog with an irritating standard message that wraps my own text. I need to either completely replace the standard message, so my text is clear, or (even better) replace the entire dialog with a modal dialog using jQuery.

So far I have failed and I haven't found anyone else who seems to have an answer. Is it even possible?

Javascript in my page:

<script type="text/javascript">   
    window.onbeforeunload = closeIt;
</script>

The closeIt() function:

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Using jQuery and jqModal I have tried this kind of thing (using a custom confirm dialog):

$(window).beforeunload(function () {
    confirm('new message: ' + this.href + ' !', this.href);
    return false;
});

which also doesn't work - I cannot seem to bind to the beforeunload event.

Aziza Kasenova
  • 1,501
  • 2
  • 10
  • 22
flesh
  • 23,725
  • 24
  • 80
  • 97
  • 1
    can you give an example of your current code and what it produces? – Owen Nov 09 '08 at 23:30
  • see here for more info: http://stackoverflow.com/questions/140460 – Ben McIntyre Feb 08 '10 at 07:09
  • More info : http://stackoverflow.com/questions/7389554/crossbrowser-onbeforeunload/10812296 – Aelios May 14 '14 at 08:29
  • In SPA you have flexibility to simulate what you want – Muhammad Umer Mar 04 '17 at 01:05
  • 3
    not possible in chrome, reference: https://stackoverflow.com/questions/37782104/javascript-onbeforeunload-not-showing-custom-message – Abhijeet Ahuja May 31 '17 at 00:40
  • Owen is correct. And, the reason behind this is security. Preventing a page from unloading is useful in web forms and such, but it can easily be exploited by a malicious site to fool the user into staying on a page. That's why web browsers implement the standard message and have this mechanism for inserting custom text. – pluckyglen Apr 22 '09 at 19:47

12 Answers12

333

You can't modify the default dialogue for onbeforeunload, so your best bet may be to work with it.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Here's a reference to this from Microsoft:

When a string is assigned to the returnValue property of window.event, a dialog box appears that gives users the option to stay on the current page and retain the string that was assigned to it. The default statement that appears in the dialog box, "Are you sure you want to navigate away from this page? ... Press OK to continue, or Cancel to stay on the current page.", cannot be removed or altered.

The problem seems to be:

  1. When onbeforeunload is called, it will take the return value of the handler as window.event.returnValue.
  2. It will then parse the return value as a string (unless it is null).
  3. Since false is parsed as a string, the dialogue box will fire, which will then pass an appropriate true/false.

The result is, there doesn't seem to be a way of assigning false to onbeforeunload to prevent it from the default dialogue.

Additional notes on jQuery:

  • Setting the event in jQuery may be problematic, as that allows other onbeforeunload events to occur as well. If you wish only for your unload event to occur I'd stick to plain ol' JavaScript for it.
  • jQuery doesn't have a shortcut for onbeforeunload so you'd have to use the generic bind syntax.

    $(window).bind('beforeunload', function() {} );
    

Edit 09/04/2018: custom messages in onbeforeunload dialogs are deprecated since chrome-51 (cf: release note)

aldoWan
  • 93
  • 1
  • 6
Owen
  • 82,995
  • 21
  • 120
  • 115
  • I was using OnBeforeUnload in order to return the user to the page, rather than actually allowing them to leave - onunload occurs after the page has unloaded surely? Also, I cannot get your onunload function to work for some reason? – flesh Nov 10 '08 at 00:45
  • 21
    I've found that the JQuery example of given at the end not to work in firefox. Stick with the simple way instead: window.onbeforeunload = function() {...} – jb. Dec 30 '08 at 01:55
  • I've gone with jb's solution, not least because the return value is significant; also, for newcomers to this, note that 'return;' in your event handler will make sure nothing pops up at all if you don't actually have any outstanding work to do or you can resolve it without talking to the user. – ijw Aug 26 '09 at 17:00
  • Adding this comment mostly so google can relate mootools or other JS libraries with the post. It seems you have to use the straight JS method for this regardless of what library you are using. It may be possible, but not worth the hassle. – TJ L Jan 13 '10 at 21:24
  • 22
    Just a note that Firefox was recently changed so that the text in the dialog can't even be customized: https://bugzilla.mozilla.org/show_bug.cgi?id=588292 – David Hammond Sep 29 '11 at 17:02
  • 15
    But how does facebook provide a custom dialog box then? for example, go to the messages page, reply to your friend's message and then before clicking send, try clicking another link. you'll see a custom dialog popup – Varun Feb 17 '12 at 21:54
  • 22
    @Varun - old news but Facebook are possibly putting handlers on the click event of all their anchors, but if you rewrite the URL in the browser or close the window, it reverts to the standard method which they have no control over. – Tabloo Quijico Jul 06 '12 at 15:26
  • 1
    @Varun I am also surprised that this answer that ways it'S impossible is flagged as the answer and have 150 upvotes... Just realized, FB's custom message is only available through links inside their site. Not if you simply navigate away... – Sébastien Richer Aug 20 '13 at 18:43
  • Is there any way to completely get rid of that onbeforeunload dialogue? I mean if I reload the page, it just reloads the page without showing that popup. – Parth Vora Dec 09 '16 at 07:02
  • 1
    *"a dialog box appears that gives users the option to stay on the current document and retain the string that was assigned to it"* - huh? This is incoherent nonsense, still uncorrected in the Microsoft docs a decade later. What does it mean for a user to "retain a string"? – Mark Amery Sep 07 '17 at 13:38
28

What worked for me, using jQuery and tested in IE8, Chrome and Firefox, is:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

It is important not to return anything if no prompt is required as there are differences between IE and other browser behaviours here.

Michael Scheper
  • 6,514
  • 7
  • 63
  • 76
grebe
  • 297
  • 3
  • 2
  • Interesting, `event.returnValue` is the only "approved" method in IE. IE [goes on to say](http://msdn.microsoft.com/en-us/library/ie/ms534372%28v=vs.85%29.aspx) "The value of this property takes precedence over values returned by the function, such as through a Microsoft JScript return statement." .. it would be nice to see a guaranteed correlation between `return` (from event) and `event.returnValue` .. –  Aug 14 '12 at 22:13
24

While there isn't anything you can do about the box in some circumstances, you can intercept someone clicking on a link. For me, this was worth the effort for most scenarios and as a fallback, I've left the unload event.

I've used Boxy instead of the standard jQuery Dialog, it is available here: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

You could attach to another event, and filter more on what kind of anchor was clicked, but this works for me and what I want to do and serves as an example for others to use or improve. Thought I would share this for those wanting this solution.

I have cut out code, so this may not work as is.

Dan Power
  • 1,141
  • 1
  • 12
  • 18
  • return 'You have made some changes which you might want to save.' did not work for me. I had to store the message in a variable say 'warning_message' and I did return warning_message. Then only it worked for me!. – Suganya Feb 16 '15 at 10:43
  • did you test in IE, Chrome, Firefox ? – Kiquenet Oct 18 '17 at 20:46
9

1) Use onbeforeunload, not onunload.

2) The important thing is to avoid executing a return statement. I don't mean, by this, to avoid returning from your handler. You return all right, but you do it by ensuring that you reach the end of the function and DO NOT execute a return statement. Under these conditions the built-in standard dialog does not occur.

3) You can, if you use onbeforeunload, run an ajax call in your unbeforeunload handler to tidy up on the server, but it must be a synchronous one, and you have to wait for and handle the reply in your onbeforeunload handler (still respecting condition (2) above). I do this and it works fine. If you do a synchronous ajax call, everything is held up until the response comes back. If you do an asynchronous one, thinking that you don't care about the reply from the server, the page unload continues and your ajax call is aborted by this process - including a remote script if it's running.

user1164763
  • 161
  • 2
  • 5
8

This can't be done in chrome now to avoid spamming, refer to javascript onbeforeunload not showing custom message for more details.

Abhijeet Ahuja
  • 5,596
  • 5
  • 42
  • 50
7

Angular 9 approach:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Browsers support and the removal of the custom message:

  • Chrome removed support for the custom message in ver 51 min
  • Opera removed support for the custom message in ver 38 min
  • Firefox removed support for the custom message in ver 44.0 min
  • Safari removed support for the custom message in ver 9.1 min
4

Try placing a return; instead of a message.. this is working most browsers for me. (This only really prevents dialog's presents)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}
Dmitry Evseev
  • 11,533
  • 3
  • 34
  • 48
Donald Powell
  • 744
  • 5
  • 10
  • 3
    return null will prevent dialog from opening – Brett Weber May 09 '13 at 17:07
  • 2
    return null will NOT prevent dialog from opening. I tried it in Chrome and it's not the case. – Ray Apr 22 '15 at 19:25
  • 2
    I can confirm Ray's comment in IE as well. Returning `null` will open a dialog with the text of "null". However, `return void(0);` will not open the dialog. – MCattle Oct 28 '15 at 17:11
  • 2
    By not putting any return statement inside the beforeunload function, the dialog will not open. – OuuGiii Aug 15 '18 at 13:23
3

I faced the same problem, I was ok to get its own dialog box with my message, but the problem I faced was : 1) It was giving message on all navigations I want it only for close click. 2) with my own confirmation message if user selects cancel it still shows the browser's default dialog box.

Following is the solutions code I found, which I wrote on my Master page.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;
Imran Rizvi
  • 7,331
  • 11
  • 57
  • 101
3

You can detect which button (ok or cancel) pressed by user, because the onunload function called only when the user choise leaveing the page. Althoug in this funcion the possibilities is limited, because the DOM is being collapsed. You can run javascript, but the ajax POST doesn't do anything therefore you can't use this methode for automatic logout. But there is a solution for that. The window.open('logout.php') executed in the onunload funcion, so the user will logged out with a new window opening.

function onunload = (){
    window.open('logout.php');
}

This code called when user leave the page or close the active window and user logged out by 'logout.php'. The new window close immediately when logout php consist of code:

window.close();
Tamas Cseh
  • 31
  • 2
  • You can use a synchronous post in the beforeunload and unload functions. Especially if you need data back from the server. Any async code within those blocks may not get completed by the time the page unloads. – jemiloii Apr 19 '16 at 17:17
1

What about to use the specialized version of the "bind" command "one". Once the event handler executes the first time, it’s automatically removed as an event handler.

$(window).one("beforeunload", BeforeUnload);
Shehary
  • 9,926
  • 10
  • 42
  • 71
  • pretty sure this is .on("beforeunload" – Sergiu Mindras Aug 23 '18 at 12:29
  • 3
    @SergiuMindras no, it's `.one()` - that attaches an event listener to listen for the event to happen only once: "Attach a handler to an event for the elements. The handler is executed at most once per element per event type." https://api.jquery.com/one/ – Sean Kendle Dec 12 '18 at 20:46
1
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

refer from http://www.codeprojectdownload.com

0

Try this

$(window).bind('beforeunload', function (event) {
            setTimeout(function () {
                var retVal = confirm("Do you want to continue ?");
                if (retVal == true) {
                    alert("User wants to continue!");
                    return true;
                }
                else {
                    window.stop();
                    return false;
                }
            });
            return;
        });