62

I have a page with a document.onkeydown event handler, and I'm loading it inside an iframe in another page. I have to click inside the iframe to get the content page to start "listening".

Is there some way I can use JavaScript in the outer page to set the focus to the inner page so I don't have to click inside the iframe?

EDIT: response to comment:

The context is the main window is a light-box-like system, except instead of pictures, it shows iframes, and each iframe is an interactive page with keydown/mousemove handlers. these handlers don't fire until I click in the iframe after showing the light-box-thing.

I'm not actually looking to "setFocus" in the traditional sense as much as "enable event handlers on the iframe contentDocument"

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Jimmy
  • 89,068
  • 17
  • 119
  • 137
  • Can you provide more context? Are you typing in the main window and expecting that text to appear (in one form or another) in your iframe? This is relevant because setting the focus inside your iframe would interfere with users typing in the main window. – cLFlaVA Dec 15 '08 at 17:08

8 Answers8

72

I had a similar problem with the jQuery Thickbox (a lightbox-style dialog widget). The way I fixed my problem is as follows:

function setFocusThickboxIframe() {
    var iframe = $("#TB_iframeContent")[0];
    iframe.contentWindow.focus();
}

$(document).ready(function(){
   $("#id_cmd_open").click(function(){
      /*
         run thickbox code here to open lightbox,
         like tb_show("google this!", "http://www.google.com");
       */
      setTimeout(setFocusThickboxIframe, 100);
      return false;
   });
});

The code doesn't seem to work without the setTimeout(). Based on my testing, it works in Firefox3.5, Safari4, Chrome4, IE7 and IE6.

cheeming
  • 1,023
  • 9
  • 14
  • 2
    I'm guessing it's because A: the iframe has to finish loading and B: safari has (had?) a bug regarding this and requires a setTimeout of at least 1 – Quickredfox Mar 18 '11 at 17:16
  • 1
    Good call on the settimeout. I find settimeout smooths a lot of issues with event code out... I'm guessing it's because the code's run in the middle of the browser's event handling, and the settimeout pulls it out and runs it after the event's all done. – Asmor Jun 30 '14 at 16:43
  • why is here iframe[0] taken like a array index? – Juke Feb 14 '19 at 21:17
27

Using the contentWindow.focus() method, the timeout is probably necessary to wait for the iframe to be completely loaded.

For me, also using attribute onload="this.contentWindow.focus()" works, with firefox, into the iframe tag

isherwood
  • 58,414
  • 16
  • 114
  • 157
danza
  • 11,511
  • 8
  • 40
  • 47
  • Using this solution combined with Jaime's suggestion down below has solved my problem in at least mozilla and webkit browsers. Still checking IE... – Christian Ziebarth Feb 20 '13 at 23:20
11
document.getElementsByName("iframe_name")[0].contentWindow.document.body.focus();
Jaime Febres
  • 1,267
  • 1
  • 10
  • 15
  • A slight variation on this solution worked in my project. My version was: `this.iframe[0].contentWindow.document.body.focus();` But I had to modify it that way to work within the plugin I am using. – Christian Ziebarth Feb 20 '13 at 23:17
5

Try listening for events in the parent document and passing the event to a handler in the iframe document.

Liam
  • 19,819
  • 24
  • 83
  • 123
3

i had a similar problem where i was trying to focus on a txt area in an iframe loaded from another page. in most cases it work. There was an issue where it would fire in FF when the iFrame was loaded but before it was visible. so the focus never seemed to be set correctly.

i worked around this with a simular solution to cheeming's answer above

    var iframeID = document.getElementById("modalIFrame"); 
//focus the IFRAME element 
$(iframeID).focus(); 
//use JQuery to find the control in the IFRAME and set focus 
$(iframeID).contents().find("#emailTxt").focus(); 
nate_weldon
  • 2,289
  • 1
  • 26
  • 32
2

Here is code to create an iframe using jQuery, append it to the document, poll it until it is loaded, then focus it. This is better than setting an arbitrary timeout which may or may not work depending on how long the iframe takes to load.

var jqueryIframe = $('<iframe>', {
    src: "http://example.com"
}),
focusWhenReady = function(){
    var iframe = jqueryIframe[0],
    doc = iframe.contentDocument || iframe.contentWindow.document;
    if (doc.readyState == "complete") {
        iframe.contentWindow.focus();
    } else {
        setTimeout(focusWhenReady, 100)
    }
}
$(document).append(jqueryIframe);
setTimeout(focusWhenReady, 10);

The code for detecting when the iframe is loaded was adapted from Biranchi's answer to How to check if iframe is loaded or it has a content?

Community
  • 1
  • 1
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
1

I discovered that FF triggers the focus event for iframe.contentWindow but not for iframe.contentWindow.document. Chrome for example can handle both cases. so, I just needed to bind my event handlers to iframe.contentWindow in order to get things working. Maybe this helps somebody ...

mile
  • 76
  • 1
  • 2
0

This is something that worked for me, although it smells a bit wrong:

var iframe = ...
var doc = iframe.contentDocument;

var i = doc.createElement('input');
i.style.display = 'none'; 
doc.body.appendChild(i);
i.focus();
doc.body.removeChild(i);

hmmm. it also scrolls to the bottom of the content. Guess I should be inserting the dummy textbox at the top.

Jimmy
  • 89,068
  • 17
  • 119
  • 137