Reputation: 34503
The goal is to create an iframe dynamically and synchronously append a SVG element to its document body.
We are trying to get this to work in Firefox.
Our research suggests Firefox resets iframes with a new document after appending iframes to the HTML. This triggers a load event, and only after this event can you successfully append content. Any content appended prior to the load event gets discarded.
The workaround, which is not ideal, is to wait for the load event then append the SVG element to the iframe.
Is it possible to avoid asynchronous behavior? We want to append the SVG element synchronously after creating the iframe.
Codepen: https://codepen.io/anon/pen/yWXjgM
var newElem = $(document.createElement("div"));
newElem.html("hi there");
var iframe = $(document.createElement("iframe"));
iframe.contents().find("body").append(newElem);
$("#box").append(iframe);
$("#box").append(newElem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="box"></div>
Upvotes: 8
Views: 2439
Reputation: 17606
tl:dr Regardless of what is done the asynchronous nature of the iframe being loaded doesn't appear to be avoidable, however there is a synchronous way to add content dynamically to the iframe via srcdoc
which "overrides" the default iframe src
attribute from being used.
It would also appear there may be a solution with using createHTMLDocument but I have yet to be successful.
srcdoc
assuming that your dynamic iframes does not load content via src
attribute
According to the HTML iframe specifications
When an iframe element is inserted into a document that has a browsing context, the user agent must create a nested browsing context, and then process the iframe attributes for the "first time".
The thing to take note is "process the iframe attributes for the first time". There is no mention to whether or not this process is synchronous nor asynchronous and it comes down to each browser's implementation.
As it has been mentioned, Chrome and Firefox have understood this process as asynchronous, which does make sense as the goal of the iframe is to load content from its src
attribute and to invoke the onload
callback.
If no src
attribute is available it'll set it to "about:blank"
It is worth mentioning that before the browser checks to see if there is a src
attribute exists, it'll first check to see if srcdoc
is available which according to MDN iframe doc:
srcdoc
Inline HTML to embed, overriding the src attribute. If a browser does not support the srcdoc attribute, it will fall back to the URL in the src attribute.
const container = document.getElementById("container");
const iframe = document.createElement("iframe");
iframe.addEventListener("load", function(){
console.log("loaded...");
});
iframe.srcdoc = `
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
`;
iframe.srcdoc += `
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="blue" />
Sorry, your browser does not support inline SVG.
</svg>
`
container.append(iframe);
<div id="container"></div>
If you're developing a web extension you will have access the mozbrowser api and thus stop
The stop() method of the HTMLIFrameElement interface is used to stop loading the content of the
<iframe>
.
Upvotes: 2