Popup when leaving website

written by paul on January 29th, 2008 @ 07:45 PM

On my current project, we had a requirement to pop up a message to the user when they leave our site (e.g., close the browser window). We discovered a number of sites talking about a window.close event, but it is not supported in modern browsers (IE 6, Firefox 2, Safari 2). The closest event is an unload event which gets fired when the page is unloaded.

We tried using this event in a javascript file that is included on every page:


window.onunload = popup;

function popup() {
  alert('I see you are leaving the site');
}

Unfortunately, an unload event is fired when the user leaves the page for any reason (such as clicking on a link). We did not want to show the popup if the user clicked on a link which stayed on the site.

Our next idea was to add an onclick to every link which would turn off the popup. Then, if the user clicks a link, nothing happens. If they leave the site another way, they get the popup.

Toby Tripp had the great idea to add these onclicks dynamically in javascript. We use prototype, so the code looks like:


staying_in_site = false;

$$('a').each(function(link) {
  link.observe('click', function() {staying_in_site = true;});
});

window.onunload = popup;

function popup() {
  if(staying_in_site) {
    return;
  }
  alert('I see you are leaving the site');
}

This code creates a variable which determines whether or not to show the popup. Then, we find every link with $$(‘a’). This is a CSS selector which selects all of the a elements. We iterate over these links and add a listener which sets the staying_in_site flag to true. Now, our popup code checks this flag and knows whether the user is staying on the site.

It is important to include this javascript at the bottom of the file (and not in the head). The javascript must be executed after the page is written or the links will not exist yet.

This solution is not perfect, but it accomplishes most of what we need.

Update (1/31/08): Simon Stewart suggested a cleaner method in the comments:


staying_in_site = false;

Event.observe(document.body, 'click', function(event) {
  if (Event.element(event).tagName == 'A') {
    staying_in_site = true;
  }
});

window.onunload = popup;

function popup() {
  if(staying_in_site) {
    return;
  }
  alert('I see you are leaving the site');
}

Instead of attaching an event listener to every link, we can attach a click listener to the whole body. Now, any click will call our function, which checks to see if you clicked on a link. Since we are not iterating over existing links, this javascript does not have to be below the links in the page.

Comments

  • Andy on 30 Jan 03:46

    How does your solutions handle forms? Do you have to register them in the same way?
  • Simon Stewart on 30 Jan 09:32

    Why not just attach a click listener to the body tag and check the original target to see if it's a link? That'll run faster, and means that you're not relying on the location of the script in the page.
  • Rob Wilkerson on 30 Jan 09:59

    With Prototype, it's easy to write the link behavior within the head using Event.oberve ( window, 'unload', ... ). As Simon mentions (sorry, I couldn't write "As Simon says" :-), then you're not reliant on script position.
  • Paul Gross on 30 Jan 13:59

    Simon, that's a great idea. We just switched our implementation to what you suggested. Andy, Simon's solution catches submit buttons as well.
  • conan on 01 Feb 03:20

    if you're responding to clicks on the document body, wouldn't you need to add staying_in_site = false; inside the conditional in case the user clicks on some random bit of background on the page, so that afterwards, when the user really leaves the page (not via a link) the popup function will behave as desired?
  • Paul Gross on 01 Feb 09:45

    Conan, you are correct. I fixed the code sample.
  • Nick on 06 Feb 14:32

    Sorry ... have not much experience in js but I don't understand how the code handles the submit.
  • Paul Gross on 06 Feb 23:35

    Nick, The click listener will catch all clicks, including submit buttons (input tags). So you can modify the line "Event.element(event).tagName == 'A'" to something that checks if the element is an input button.
  • JC Tenney on 28 Mar 07:38

    When I moved the above code in to my site, I got the following error: element has no properties (prototype.js line 2244). Any thoughts as to what it could be?
  • Paul Gross on 28 Mar 10:28

    JC, can you give me more information? What line in your code (not prototype) is causing the error?
  • JC Tenney on 29 Mar 10:42

    That is the problem, I don't know what line of code is causing the problem. I don't know what the problem is. When I look at the stack it says the error is coming from this line: ERROR HERE->Event.observe(document.body, 'click', function(event) { if (Event.element(event).tagName == 'A') { staying_in_site = true; } }); I stepped into the prototype function and it said that element is null.
  • Paul Gross on 30 Mar 11:21

    JC, do you have the code in the body or in the head? If it is in the head, document.body is null. You should either move the code to the body or wrap it with a dom:loaded event: http://www.prototypejs.org/api/document/observe.
  • Gavriel on 15 Apr 12:03

    Nice solution! I found an annoying bug though: when I refresh the page it pops up the alert. Does anyone have a solution to this?
  • Sig on 14 May 20:24

    Hello, I have a couple of questions about your solution (my js skills are poor so I apology if the questions look like silly) 1- what exactly the script should do? does it open a popup when the user closes the browser tab? If so 2- what have I to do in order to make it working? I copied the script at the end of my body page but nothing happens. Thanks and have a good 1!

Post a comment

Options:

Size

Colors