react-svg: injecting SVG markup into the DOM so CSS can reach it
:art: A React component that injects SVG into the DOM.
At a glance
- What is it?
- react-svg is a React component that fetches an SVG at run time and injects its markup into the document, so page styles, scripts and accessibility attributes can apply to it. It suits applications where the icon URL is only known once the app is running, not a build-time icon pipeline.
- Who is it for?
- react-svg is a good fit for an application that pulls icons from a content system, a CDN or a user upload, where the path is assembled at run time and the markup has to be reachable by CSS or by your accessibility tooling.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why you would inject rather than embed
The when-to-use section is the most useful part of the documentation, and it is a decision tree rather than a feature list. The component fetches an SVG from a given URL and injects its markup into the DOM, and fetched SVGs are cached so multiple uses of the same SVG only require a single request. The cost is stated plainly, a network request and two wrapper elements, and the documentation explains that it earns that cost in exactly one case, when the SVG's URL is not known until the app runs and the markup has to be reachable by CSS. An img tag renders an SVG but its contents cannot be styled, animated or scripted from the page, and that is the whole reason injection exists. The three branches are then clear. If the SVGs live in your repository and are known at build time, the documentation points you at a build-time transform instead, naming SVGR, a Vite plugin and your bundler's SVG loader, because those compile each file to a React component with no runtime fetch and tree-shake the unused icons. If the URL is only known at run time, whether from a content system, an API, a user upload or a CDN-hosted icon set, that is what this component is for. And if you only need to display the image, an img tag is cheaper than either option.
The component, the wrapper and the two wrapper elements
The basic usage is a single import and a single element, and the prop list is short enough to scan:
import { ReactSVG } from 'react-svg'
const App = () => <ReactSVG src="svg.svg" />The props table is where the real surface is, and the defaults are chosen conservatively. The src prop is the only required one. There are two lifecycle hooks, beforeInjection and afterInjection, each taking the SVG DOM element and each defaulting to a no-op, and the before hook is documented as the place to restyle, add a class to or sanitise the element. There is a loading element rendered inside the wrapper until the SVG is injected, and a fallback element rendered inside the wrapper if an error occurs, and when either is unset nothing is rendered in its place. The wrapper prop chooses the element type and accepts a div, a span or an svg, defaulting to a div, which is how you control the extra markup in the DOM, and the two wrapper elements referred to in the cost discussion come from the injection and the wrapper. The desc prop fills the SVG description element, and when it is set a unique id is added and the accessible description reference is set on the SVG, with an empty string doing nothing.
The options that change behaviour rather than appearance
Three props carry real decisions rather than styling. The evalScripts prop controls whether script blocks found inside the SVG are run, and it takes always, once or never, with the default of never and the explicit advice to leave it there for SVGs you do not control. The httpRequestWithCredentials prop decides whether cross-site access control requests for the SVG carry credentials, defaulting to false, which is the safe default for a component that fetches arbitrary URLs. The useRequestCache prop controls the caching of fetched SVGs and defaults to true, which is what makes the second use of an icon free. The renumerateIRIElements prop decides whether addressable elements inside the SVG get their identifiers made unique, defaulting to true, and it matters because two copies of the same SVG on a page will otherwise contain the same identifiers for things like clip paths, gradients, masks and paths, and the references to them collide. The onError prop is called with an unknown value, and the documentation is specific that errors thrown from the injection hooks are routed to it and render the fallback, the same as an error raised by the injection itself.
The loading delay, which is a layout decision
The loadingDelay prop is the most opinionated feature in the API and the documentation explains the reasoning at length, which makes it worth reading. The delay is the number of milliseconds to wait before rendering the loading state, and at the default of zero it renders immediately. The advice is to set a value when the injection finishes sooner, whether that is a warm request cache, a localhost or file read, or a warm CDN edge, in which case the loading state never renders at all. The reasoning is about what the loading state is for. If it is a spinner, a sub-second appearance is worse than none, because the user cannot tell what flashed. If it is a skeleton sized to hold the space the SVG will take, the delay is wrong, because delaying trades one layout shift for two. The guidance gives 200 to 300 milliseconds as the usual industry choice, and notes that the delay applies to the loading state only, since the fallback always renders as soon as the error arrives, because an error costs a round trip that no cache short circuits.
The source can be a URL, a data URL or a sprite
The src prop is more capable than it first appears, and the documentation enumerates the forms it supports. There are fetchable URLs, which may be relative or absolute. There are data URLs in the image and SVG plus XML form, either URL-encoded or base64. And there are sprite sheets referenced by a fragment identifier, in the form of a sheet path followed by a hash and a name, and the repository has an example directory for the sprite usage and another for the data URL form. The consequence of the sprite form is worth understanding, because it is the case where a single request serves many icons, and the caching behaviour then does the work that the sprite is already doing. The examples directory lists the range of situations the author has covered, with directories for accessibility, API usage, basic usage, the before injection hook, CSS animation, CSS in JS, data URLs, an external stylesheet, fallbacks, an iframe, loading, no extension, sprite usage, server-side rendering, styled components, SVG wrapper and TypeScript.
A small, carefully packaged package
The package metadata shows a project that pays attention to what it ships. The type is commonjs, and the exports map gives separate import and default conditions with their own type declarations for each, so a bundler that understands the import condition gets the ES module and its declaration file while a CommonJS consumer gets the other build. The main, module and types fields point at the corresponding built artefacts, and the files list publishes only the dist directory and the source. The sideEffects flag is false, so bundlers can drop the package if it is unused. There is a size-limit configuration with a two kilobyte gzip budget for the ES module bundle and two and a half for the CommonJS one, and a script that runs it as part of the test command, so the size claim is enforced rather than stated. The build uses tsdown for bundling with a clean step, and the postbuild runs two packaging checks, one for the type definitions across export conditions and one for the package shape. The test script runs the type check, the lint, the build, the size check and then four separate test configurations covering the source, the distributed build, the CommonJS build and the ES module build.
Editorial conclusion
react-svg is a good fit for an application that pulls icons from a content system, a CDN or a user upload, where the path is assembled at run time and the markup has to be reachable by CSS or by your accessibility tooling. It is the wrong tool for icons that live in your repository and are known at build time, because the documentation is explicit that a build-time transform is the better route there, compiling each file to a component with no runtime fetch and tree shaking of unused icons. It is also the wrong tool if you only need to display the image, since an img tag is cheaper than either option. It is the wrong tool if you cannot control where the SVG comes from, because the component will happily fetch and inject markup from another origin, which is a security decision you have to make. Before adopting it, read the security section and the script evaluation option, and leave script execution off for anything you do not control. The project is MIT licensed, the last push was on 2026-10-19, and the current release is v19.2.2 from the same day.
Frequently asked questions
When should I use react-svg instead of an img tag or a build-time transform?
Use react-svg when the SVG's URL is only known at run time, such as from a content system, an API, a user upload or a CDN-hosted icon set, and the markup has to be reachable by CSS. If the SVGs live in your repo and are known at build time, use a build-time transform such as SVGR instead, and if you only need to display the image, an img tag is cheaper than either.
How do I install and use react-svg?
The package is react-svg, and the basic usage is a single import and a single element, with the ReactSVG component taking a src prop that is the only required one. The wrapper prop chooses whether the surrounding element is a div, a span or an svg, and defaults to a div.
Does react-svg execute scripts inside an SVG?
Only if you ask it to. The evalScripts prop takes always, once or never and defaults to never, and the documentation advises leaving it at never for SVGs you do not control. Errors thrown from the injection hooks are routed to the onError prop and render the fallback, the same as an error raised by the injection itself.
What is the loadingDelay prop for in react-svg?
It is the number of milliseconds to wait before rendering the loading state, and the default of zero renders it immediately. The documentation recommends setting it when the injection finishes sooner, for example from a warm cache or a warm CDN edge, because a sub-second spinner is worse than none, while a skeleton sized to hold the SVG's space should stay at zero. Two hundred to three hundred milliseconds is given as the usual choice.
How large is the react-svg package?
The package metadata sets a size limit of two kilobytes gzipped for the ES module bundle and two and a half for the CommonJS one, and the size check is part of the test command, so the budget is enforced in CI rather than only documented. The project is MIT licensed, the current release is v19.2.2 from 2026-10-19, and the last push was on the same day.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tanem-react-svg)Was this useful?