Programmatically clicking a link in Javascript

More accurately, this would be called actuating a link (i.e. the process of setting the link's behavior into motion, if you will.) In other words, you have a link:

<a id = 'bingLink' href = "http://www.bing.com">Bing</a>

And you want to programmatically make that link do its thing. This usually means having the browser navigate to the URL specified link's href attribute (though, it can also mean executing some click handler if one happens to be specified on said link.)

To be honest, I don't think there are a ton of real-world uses for this, but there are a few. And depending on your needs, it may not be trivial to accomplish this in a cross-browser fashion. For example:

var myLink = document.getElementById('myLink');
myLink.click();

The above will do the trick in IE, because IE supports .click() on links. Most other browsers don't though, so that's not an all-encompassing solution.

One (partial) solution in non-IE browsers might be to read the href attribute from a given link and then use Javascript to make the browser navigate to to the URL specified by href that way:

function actuateLink(link)
{
     window.location.href = link.href;
}

This is not a complete solution for a couple of reasons:

  1. Navigating by setting window.location.href blows away the document.referrer property.
  2. Any click event handler wired to the link will not execute.

For anyone who has read my post about Re-routing events in Javascript post, you'll know that it is possible to simulate an event though the use of .dispatchEvent(..).

Here's a brief refresher of the part most relevant to this discussion:

var myEvt = document.createEvent('MouseEvents');
myEvt.initEvent(
   'click'      // event type
   ,true      // can bubble?
   ,true      // cancelable?
);
document.getElementById('myLink').dispatchEvent(myEvt);

This approach will ensure that any click event handlers will fire as desired (though, it's worth nothing that you'd have to handle mousedown, mouseup, keydown, keypress etc... separately,) but it does NOT actuate the link!

This might surprise you. Dispatching a click event to a link doesn't actually cause the browser to navigate to the URL specified by that link's href property. This actually isn't shocking to me, personally. A little surprising, but not shocking.

Anyway, one option is to dispatch the click event and then use window.location.href. This should achieve (some of) the desired effect, but again, the document.referrer will not be preserved if you do this. Also, if the event handler prevents the default action, this method will not honor the code that prevents the default action (i.e. the link will navigate despite the code that attempts to prevent it from doing so.)

You can work around the window.location.href problem by creating a <form> element, settings its action attribute to that of the link's href attribute and then submitting the form through myForm.submit(), but the problem regarding preventing the default action remains.

A 95% Solution

Is there a 100% perfect solution to this problem? Probably, but I'm not 100% perfect. I'm only 95% perfect, so I give you my 95% solution:

function actuateLink(link)
{
   var allowDefaultAction = true;
      
   if (link.click)
   {
      link.click();
      return;
   }
   else if (document.createEvent)
   {
      var e = document.createEvent('MouseEvents');
      e.initEvent(
         'click'     // event type
         ,true      // can bubble?
         ,true      // cancelable?
      );
      allowDefaultAction = link.dispatchEvent(e);           
   }
         
   if (allowDefaultAction)       
   {
      var f = document.createElement('form');
      f.action = link.href;
      document.body.appendChild(f);
      f.submit();
   }
}

To use it:

actuateLink(document.getElementById('bingLink'));

This code is self explanatory, right?

If .click() is available, let's use that. If not, let's try to do a W3C-style create and dispatch event. Then, in order to maintain the document.referrer property, we'll use a form submission, but we only want to submit that form if the event handler (if there is one) for the click event doesn't explicitly prevent the default action.

This isn't a 100% perfect solution because, actuating a link in this manner is only going to invoke click handlers and navigate to the URL of the link's href attribute (if appropriate to do so.) It isn't going to invoke handlers for any other types of events. And I'm not about to create and dispatch every possible kind of event. Besides, I think we can all agree that click is by far the most common scenario.

So there ya go. Programmatically clicking (or more accurately, actuating) a link with Javascript. Enjoy!

(Tested: Firefox 3.5.7, IE8, Opera 10.01, Safari/Win 4.0.3, Chrome 3)

26 Responses

  1. popus Says:

    Hello, this script is very very slow with FF4. Did you know why ?

  2. sstchur Says:

    No, I'm not sure why it'd be any slower in FF4 than in any previous version of Firefox. My only guess would be that creating and dispatching events may have changed somewhat — perhaps it's not an efficient mechanism in FF4.

  3. Tarik Says:

    Cheers dude works like a charm

  4. Josh Says:

    I see that webkit browsers are appending a question mark to the end of the URL. I can't seem to figure out why that is and how to correct it. Any idea?

  5. Josh Says:

    Nevermind. I'm an idiot. I'm still not sure how to get rid of the question mark, but at least I know why it's adding it.

  6. sstchur Says:

    LOL. Glad you figured it out. So it didn't have anything to do with the code from the blog post then?

  7. Brett Says:

    Thank you very much! This was making me nuts!

  8. sstchur Says:

    No problem! Glad you found it helpful.

  9. colin Says:

    Very helpful! Thanks.

    Only thing I would add would be to set the target of the form to the target of the link. ( form.target = link.target; ). Hopefully that brings you up to 96%

  10. sstchur Says:

    ^^ This is a good suggestion, thanks!

  11. alin Says:

    jQuery makes this whole process easier. If you use jQuery in your page, you can do $('selector').trigger('click');

  12. sstchur Says:

    Unfortunately, jQuery doesn't seem to quite work in this case (at least, not in my limited testing). I don't know what .trigger(..) is doing under the hood, but if it's dispatching a click event manually, then it's not surprising that it wouldn't work. You might remember this comment from my post: "Dispatching a click event to a link doesn't actually cause the browser to navigate to the URL specified by that link's href property."

    The good news though, is that more and more browsers seem to be supporting .click these days (only IE did at the time I originally wrote the post). Seems that at least Chrome does as well now, and perhaps FF does too (I didn't check though).

  13. ankit Says:

    Thanks a lot !!
    you literally made my day :-)

  14. Axel Says:

    Hi, thanks for this post – I really appreciate the knowledge share. I do have one problem though. On Safari 5.1.3 (OS Lion), the script is redirecting to the baseURI of the event e instead of the link's href. When commenting this out, to force a form submit, it does the same thing and ignores the action attribute! Is this a bug or is something wierd going on? Works in every other browser though!

  15. sstchur Says:

    Hmm… I think I do have a Mac at work with latest Safari on it (I use it so rarely that I honestly don't know what version I'm running). I will double-check tomorrow and see if I can repro this (and hopefully come up with a solution). Did you try Safari/Windows? Would be curious to know if it only repros on Safari/Mac.

  16. Axel Says:

    Thanks for the quick reply. Just an update from me: it is the form submission that is the issue; removing this code means the script works, but I guess you lose the document.referrer property. I'll continue to do some more testing. I wonder if this is some kind of Apple js security policy/bug.

    I will give Safari/Windows a try later tonight. Interesting to hear that it seems Apple are no longer updating Safari for windows.

  17. Axel Says:

    Just another quick update. Even without the form submission, the document.referrer value is looking correct. So for now I think I am happy with using 66.66% of your 95% solution :)

  18. MoonWatch Says:

    Have you tried doing like so: jQuery('a#bingLink')[0].click(); ? It works for me in Google Chrome 23.0.1271.95 on Linux :)
    You might have to do it inside of a jQuer(document).ready() handler, but it should still work.
    Note, that jQuery('a#bingLink').click(); will not work – the "[0]" part references the DOM object as far as I remember(vs the jQuery object when you don't use the "[0]").

  19. Sean Says:

    How to click on the voice search button in webkit when the input type is text and x-webkit-speech enabled?

  20. Ben Amada Says:

    When submitting the form, same as Josh, the URL it would end up at after submission would have a question mark with nothing else after it.

    In my case, the form action was set to "/some-folder/?x=1&y=1", and the URL after form submissions was http://www.example.com/some-folder/? (the remaining querystring values are missing). This is in Chrome v28.

    A simple solution for this was to set an explicit "method" on the form of "post". Setting it to "get" (which appears to be the default form method) ended up with the same trailing ?. So needed the form method to be "post".

  21. Richard mcfriend Says:

    Hey dude
    Nice job there. Its not 100% but its a nice attempt. You tried a lot.

  22. David Says:

    Hi.

    Have you tried in Safari 5.1.x..???

    I can't image how to simulate click for this browser.

    thanks

  23. sstchur Says:

    Are you in Safari Mac or Windows? Both? I honestly haven't tried, but if I have time, I can give it a quick attempt.

  24. scipper Says:

    very nice, solved the problem in IE 10/11 for me!!
    +1

  25. Teresa_ Says:

    This is great! I need just a little more and I can't figure out how to do it. Somewhere around f.action = link.href; I want to pass a variable back $_POST. I tried a hidden input with
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('value', val);
    document.body.appendChild(input);

    And then I tried to add a query string… ?newvar='somethingtopass'

    Can you give me a hint or a reference?
    Thanks!

  26. admin Says:

    Well the default method for a FORM is going to be GET, so perhaps you need to add a line that set's the form's method to POST?

Got something to say?

Please note: Constructive criticism is welcome. Rude or vulgar comments however, are not and will be removed during moderation.