10

I've used window.onbeforeunload to display a custom message when a user attempts to leave a site.

Example:

window.onbeforeunload = function(){
  if(some_condition){
    return "Are you sure you want to navigate away from this page?\nAll unsaved changes will be lost.";
  }
};


+--------------------------------------------------------+
| Are you sure you want to navigate away from this page? |
| All unsaved changes will be lost.                      |
|                                                        |
|          [ Yes ]  [ Cancel ]                           |
+--------------------------------------------------------+

However, I'd like to enhance this a bit. If possible, I'd like to use a custom modal form instead of the generic popup.

Is there a way to do this?

maček
  • 76,434
  • 37
  • 167
  • 198

8 Answers8

8

Binding to a html has worked very well for me instead of unload. The reason is well explained in another answer here.

$("html").bind("mouseleave", function () {
    $('#emailSignupModal').modal(); \\or any modal
    $("html").unbind("mouseleave");
});

If you want to show the modal only once in a day or on any other particular condition match then you can use cookies.

Community
  • 1
  • 1
Mandeep Janjua
  • 15,583
  • 4
  • 29
  • 24
  • 2
    It's a poor solution as this event is fired (in Chrome) every time user move the mouse outside the document. – wawka Aug 22 '18 at 14:55
  • @wawka! sorry, you do not like my solution. Although, it is not far away from other accepted answers on this page. So, looks like your knowledge about events is limited. Please give it a read. Thx – Mandeep Janjua Aug 22 '18 at 20:11
  • For sure my knowledge is limited. Nobody knows everything ;) However, it doesn't change the fact that this solution is not correct or at least not universal. Maybe, jquery changes when this event is caught, but if use just native addEventListener on ```document.documentElement```, Chrome fires the callback everytime you leave the browser window (eg. when you want to change the tab). There is no need to feel resentful :) – wawka Aug 24 '18 at 05:06
  • Ugh. If I went to a site that did this I would never return. Obviously there's such a thing as multiple windows being used at once, this would be incredibly annoying. – Madbreaks Jan 03 '20 at 17:10
6

The unload event will fire when a user tries to navigate away. However, if you use a DIV as a pop-up the browser will navigate away before the user has a chance to read it.

To keep them there you'd have to use a alert/prompt/confirm dialog boxes. (as far as I know)

John Strickler
  • 25,151
  • 4
  • 52
  • 68
  • Hmm, that's what I was worried about. Thanks anyway. – maček Oct 14 '10 at 04:17
  • And how does Facebook do it then? – Armin Hierstetter Mar 17 '17 at 08:41
  • 1
    @ArminHierstetter It's possible that browsers have updated their APIs in the 6 1/2 years since this answer was given – John Strickler Mar 17 '17 at 16:21
  • @ArminHierstetter or they bound a click handler to all their links – Huangism Apr 10 '17 at 15:11
  • @ArminHierstetter They don't _necessarily_. When you click the box to write a status, you can no longer click on any links on the site outside of the post box. So they are just triggering an action when you try to leave/close the post box, which isn't leaving the page. If you try to refresh the page when in the middle of writing a status, you will see the normal browser alert box. – Josh Riser Apr 12 '17 at 13:32
  • Not possible to use unload to achieve this, per the docs: *"UI interactions are ineffective (window.open, alert, confirm, etc.)"*. `beforeunload` is only (limited) option. https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event – Madbreaks Jan 03 '20 at 17:08
2

another alternative I see sites use for this functionality is creating an action when the user scrolls off the page like when they scroll to the address bar like this site does http://www.diamondcandles.com/ this can be done using mouseleave event on the body element. For example:

$( document ).ready(function() {

  $("body").bind("mouseenter",function(){
   /* optional */

  }).bind("mouseleave",function(){
    if(!$.cookie('promo_popup')) {

      /* do somthing (ex. init modal) */

      /* set cookie so this does not repeat */   
      $.cookie('promo_popup', '1', { path: '/' });

    }
 });
});
Nick Lucas
  • 317
  • 2
  • 5
  • 3+ years later, thanks for this solution, but it's a little too aggressive yet still fails to capture all ways that a user could navigate away from the page. – maček Feb 13 '14 at 05:52
2

Is there a way to do this?

Nope.

You are stuck with the prompt the browser gives you.

epascarello
  • 204,599
  • 20
  • 195
  • 236
  • @Moin, what you posted is hijacking all of the click events on the page. Use the refresh button, back button, close the browser. It will fail. – epascarello Oct 13 '10 at 21:09
  • @macek, There is no source. It is known fact. You can not change alerts, confirms, prompts, or any other windowed element. You can not change the onbeforeunload dialog. These windows are standard for a reason, so people know what they are getting. If you could prevent someone from leaving with your idea, a hacker would love it. Just like the pop up windows in the old days where you could hide the close button. Some people had good intentions with there being no close, but advertisers had "good" intentions too. – epascarello Oct 13 '10 at 21:15
  • 1
    epascarello, I'm voting this down because this is not a useful answer if you can't back it. Saying it is a "known fact" doesn't help. By the way, you *can* change the content of the onbeforeunload dialog. See my code example above. Because there was some leeway here, I was wondering if there was more. – maček Oct 14 '10 at 04:16
  • @macek, There is nothing to back it up. Documentation on onbeforeunload is basically non existant since it is a MS made up thing that other browsers copied. Look at the docs https://developer.mozilla.org/en/DOM/window.onbeforeunload and you will see they give zippo information on it. You can add a message to the dialog, BUT you can not change the look and feel which is what you are implying. Changing the text is hardly leeway since you can do that with all of the other windowed elements [alert, confirm, prompt]. You are hoping for a miracle of an answer and you will not get one. – epascarello Oct 14 '10 at 04:36
  • And how does Facebook do it then? – Armin Hierstetter Mar 17 '17 at 08:42
  • @ArminHierstetter how does Facebook do what? – epascarello Mar 17 '17 at 10:12
  • As far as I can see Facebook is not an exception. It also uses browser native prompt for that. This is the most accurate answer right now. – wawka Aug 24 '18 at 05:18
  • @Madbreaks The poster in this question from 10 years ago asked about getting rid of the dialog, that was never possible. Yes some browsers let you change the text, but the question was altering the dialog to be a custom one. – epascarello Jan 03 '20 at 17:27
  • @epascarello my bad, I misread. Apologies to decade-younger you. :) – Madbreaks Jan 03 '20 at 19:35
1

If they click the back button or something similar, I believe the alert/prompt/confirm boxes are your only option.

However, you can probably listen for specific keypress events, like ctrl/cmd + w/r, and interrupt those with a dialog.

hookedonwinter
  • 12,436
  • 19
  • 61
  • 74
1

Hey this will help you to show a popup model or window when a user leaving your website. Before using this code please try Run code snippet

<!DOCTYPE html>
<html lang="en">
<head>
  <title>show popup when user leaves website</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
  <h2>Show popup when user leaves your website</h2>
  

  <!-- Modal -->
  <div class="modal fade" id="myModal" role="dialog">
    <div class="modal-dialog">
    
      <!-- Modal content-->
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal">&times;</button>
          <h4 class="modal-title">Hey! wait for free __________</h4>
        </div>
        <div class="modal-body">
          <p>Get this code for free</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        </div>
      </div>
      
    </div>
  </div>
  
</div>

<script>
$(document).ready(function(){
  
  $("html").bind("mouseleave", function () {
    $('#myModal').modal();
    $("html").unbind("mouseleave");
});
});

</script>

</body>
</html>
Santosh
  • 9
  • 1
0
var confirmOnPageExit = function (e) {
// If we haven't been passed the event get the window.event
e = e || window.event;

var message = "Are you sure you want to navigate away from this page? All unsaved changes will be lost.";

// For IE6-8 and Firefox prior to version 4
if (e) 
{
    e.returnValue = message;
}

// For Chrome, Safari, IE8+ and Opera 12+
return message;
};

window.onbeforeunload = confirmOnPageExit;

Lucky
  • 197
  • 1
  • 1
  • 9
0

I've just had to do this for a project.

I set rel="external" on all external links then used JS/Jquery to detect if the link has this attribute, and if it does - prevent the default behavior and instead fire a modal.

$('a').on('click', function(e){

  // Grab the url to pump into the modal 'continue' button.
  var thisHref = $(this).attr('href');

  // Grab the attr so we can check if its external
  var attr = $(this).attr('rel');

  // Check if link has rel="external"
  if (typeof attr !== typeof undefined && attr !== false) {

    // prevent link from actually working first.
    e.preventDefault();

    // insert code for firing your modal here! 

    // get the link and put it in your modal's 'continue button'
    $('.your-continue-button').attr('href', thisHref);

  } 

});  

Hope this helps.

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Tom Durkin
  • 71
  • 9