I am building an interface to preview animations applied to SVGs. I am trying to target an SVG's internal paths for animation with the Velocity.js library, in React. I'm using create-react-app.
I am able to drag-and-drop a .svg file into a react-dropzone input, which provides a callback with a File
object. I can convert the File
object to a base64 encoded DataURL, which I can then provide to an <object>
tag. This renders the SVG with the full, expanded xml markup.
return (
<object style={{
width: '100%'
}}
id={`svg-${uuid}`}
type="image/svg+xml" data={dataURL}
/>)
Any attempt to access the contentDocument
of the SVG, using javascript, (for the purposes of targeting g
and path
elements directly for animation) results in the following error:
document.getElementById('svg-665790ae-2a36-446e-9ea9-856442e8b1dc').contentDocument
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLObjectElement':
Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.
I am working on a local development environment, serving the React application on localhost:3000
.
As a possible workaround, I uploaded the SVG in question to a remote AWS S3 storage bucket. I then retrieve the SVG via the remote URL, and am trying to render that, in some way. I have tried the following approaches:
<svg>
<use xlinkHref={url}></use>
</svg>
This results in the following markup, but no visible SVG:
<svg>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://s3.amazonaws.com/.../example.svg">
</use>
</svg>
<object>
tag
<object
style={{
width: '100%',
}}
id={`svg-${uuid}`} type="image/svg+xml" data={url}
/>
This results in the following markup, without a visible SVG, and it causes the SVG to be immediately downloaded as a file by the browser.
<object id="svg-..." type="image/svg+xml" data="https://s3.amazonaws.com/.../example.svg" style="width: 100%;"></object>
react-inlinesvg library
This library makes an XHR request to retrieve the SVG and then embeds it into the DOM.
<Isvg src={url}/>
This results in the following error:
XMLHttpRequest cannot load https://s3.amazonaws.com/.../example.svg.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access.
First I mounted a simple <img>
tag with the SVG url:
return (
<img
ref={node => this.testSVG = node}
src={url} id="svg" type="image/svg+xml" />
)
This also results in the above XMLHttpRequest
error. Attempts to call SVGInjector
, from componentDidMount
, with either the node ref
(i.e., SVGInjector(this.testSVG)
), or in this manner:
const el = document.getElementById('svg');
SVGInjector(el);
causes the warning to disappear but results in only a broken image tag displaying.
Any help in resolving these CORS
warnings or guidance on the correct way to embed SVG in the DOM, in React, for the purposes of animation, would be greatly appreciated. Perhaps what I need to do is download the image via the server, and temporarily serve it directly from the server filesystem, e.g., from the /public
folder. This is not my preferred approach, as I am already using AWS S3 for image hosting.