Select an SVG inside an <object> tag with JavaScript
One of the incredible things about SVGs is the fact that they are dynamic; they can be altered when on the page. If you use an SVG directly in the markup you can access it directly. You can see this approach used on http://nice-letterform.com.
However, it’s also possible to place SVGs into markup with an <object> tag. Here’s an example:
<object id="svgObject" data="img/svgfile.svg" type="image/svg+xml" height="50" width="50">
Your browser doesn't support SVG
</object>
In this case, an image called ‘svgfile.svg’ is in an ‘img’ folder and this <object> will pull it in and place the SVG contents into the DOM. This then provides full access to the SVG DOM (which crucially differs from an HTML DOM). If the browser doesn’t have support, the enclosed text message will be shown.
display: none;
)So now it’s in the DOM, we want to amend that SVG with JavaScript. Shouldn’t be a problem. As already noted, if you look in the Dev Tools the SVG DOM is clearly there.
Lovely. Except as a JavaScript amateur, I tend to lean on jQuery (and I’m not too great with that either). Here’s the most important thing you can know in relation to this subject: YOU CAN’T SELECT PARTS OF THE SVG INSIDE AN OBJECT DIRECTLY WITH JQUERY. Phew. Hope you got that. The abridged reason: jQuery only understands the HTML DOM and not the SVG DOM.
However, don’t sweat that. You just want to select your SVG internals. Am I right? We can do it easily with good ol’ JavaScript. To aid understanding, imagine this is the contents of our SVG:
<svg height="40px" width="40px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
<rect id="svgItem" width="800" height="800" fill="red"></rect>
<circle cx="400" cy="400" r="400" fill="blue"></circle>
</svg>
As you can see, the rectangle is red by default. Let’s change that with JavaScript:
window.onload=function() {
// Get the Object by ID
var a = document.getElementById("svgObject");
// Get the SVG document inside the Object tag
var svgDoc = a.contentDocument;
// Get one of the SVG items by ID;
var svgItem = svgDoc.getElementById("svgItem");
// Set the colour to something else
svgItem.setAttribute("fill", "lime");
};
You’ll notice in the above code that the fun stuff has been enclosed in a window.onload function. This simply ensures that the SVG and the main DOM is loaded before we start trying to manipulate it.
I’m also aware that there is a plugin for jQuery called jQuery.svg that gives jQuery the super powers to select SVGs internals in this way but I didn’t want another dependency.
The key here is the contentDocument
that grabs the inner (SVG) document. So don’t be put off, even if the thought of non-jQuery JS makes you tremble. It’s nice and simple with native JavaScript.
Every time I attempt this, I end up with this nasty error:
“Uncaught SecurityError: Failed to read the ‘contentDocument’ property from ‘HTMLObjectElement’: Blocked a frame with origin “null” from accessing a frame with origin “null”. Protocols, domains, and ports must match. ”
I have absolutely no idea what that means, but I doubt it’s because the page isn’t fully loaded, as I used onload = “myFunction()” on the body.