For the past year, I have been working on a web application that relies heavily on inline frames (aka iframe
s). During the course of development, we have run into some interesting issues and I thought I would record some of these for posterity.
The W3C specification for the IFRAME
element states the following document type definition:
<!ELEMENT IFRAME - - (%flow;)* -- inline subwindow -->
<!ATTLIST IFRAME
%coreattrs; -- id, class, style, title --
longdesc %URI; #IMPLIED -- link to long description
(complements title) --
name CDATA #IMPLIED -- name of frame for targetting --
src %URI; #IMPLIED -- source of frame content --
frameborder (1|0) 1 -- request frame borders? --
marginwidth %Pixels; #IMPLIED -- margin widths in pixels --
marginheight %Pixels; #IMPLIED -- margin height in pixels --
scrolling (yes|no|auto) auto -- scrollbar or none --
align %IAlign; #IMPLIED -- vertical or horizontal alignment --
height %Length; #IMPLIED -- frame height --
width %Length; #IMPLIED -- frame width --
>
The key thing I’m interested in here is the name
attribute. Our particular application allows iframe
s to fire events which are then caught by the parent window. In order to identify the source of these events, the iframe
s send along their name
(accessed via window.name
).
If you have an iframe
like the following in your web page:
<iframe frameborder="0" name="bob" src="/some-page"></iframe>
And /some-page
contains the following HTML:
<!DOCTYPE html>
<title>Test</title>
<script>
document.write('My name is ' + window.name);
</script>
Then the iframe
should output the following:
My name is bob
Here’s that in action:
However, if you are dynamically creating iframe
s with JavaScript (perhaps to avoid BFCache bugs) then you may run into some issues where window.name
is undefined
in Internet Explorer 6 and 7.
Specifically, if you create an iframe
and set its name like so:
<script>
(function () {
var iframe = document.createElement('iframe');
iframe.src = '/some-page';
iframe.name = 'bob';
document.body.appendChild(iframe);
}());
</script>
Then /some-page
will report the following:
My name is
Again, a live demonstration (note that this will only be broken in Internet Explorer):
The same will occur if you use jQuery:
<script>
$(function () {
$('<iframe/>', {
src: '/some-page',
name: 'bob'
}).appendTo(document.body);
});
</script>
The issue arises because the name
of an iframe
cannot be changed in Internet Explorer, much like the type
attribute on input
(there is a caveat in the jQuery documentation about the type
issue when creating elements).
This means that you must set the name
attribute on creation of the element, not afterwards.
With jQuery, it’s a case of doing the following:
<script>
$(function () {
$('<iframe name="bob"></iframe>').attr({
src: '/some-page'
}).appendTo(document.body);
});
</script>
With pure JavaScript it is slightly trickier as you can no longer use document.createElement
. However, you can create a temporary container element (say, a div
), and then modify that element’s innerHTML
to create your iframe
with its name
from the beginning. You can then take your newly created iframe
and insert that directly into the DOM (without ever inserting your temporary div
) like so:
<script>
(function () {
var temp = document.createElement('div');
temp.innerHTML = '<iframe name="bob" src="/some-page"></iframe>';
document.body.appendChild(temp.firstChild);
}());
</script>
(This is actually what jQuery does internally in the prior example.)
In this way, all browsers should now correctly report:
My name is bob
And a live demonstration: