Skip to content
This repository was archived by the owner on Sep 8, 2026. It is now read-only.

Latest commit

 

History

147 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

svgin-react

Archived. This repo has been folded into the svgin monorepo as packages/react, alongside a new svgin-element package and the apps/tryit demo. Development, issues, and releases (still published to npm as svgin-react) now happen there. This repo is kept read-only for history.

npm version npm downloads minzipped size CI MIT License

svgin-react fetches an SVG from a URL, or takes raw SVG markup you already have, and renders it as a real, styleable React <svg> element instead of an <img>. Sanitized by default with DOMPurify, so it is safe with SVGs you did not create yourself. Works in the browser and in React Server Components.

import { SvgIn } from 'svgin-react';

<SvgIn src="/icons/alert.svg" width={24} fill="#f00" />

Try it live: paste your own SVG markup and see exactly what the sanitizer strips, or click through the RSC, Suspense, Shadow DOM, provider-defaults, and lazy-loading demos.

Why svgin-react

An <img src="icon.svg"> cannot be styled with CSS: no color changes, no path animation, no targeting inner elements. Inlining the SVG markup fixes that, but inlining raw markup from a URL you do not fully control is a real security risk (an SVG can carry <script> tags, onload handlers, and other ways to run JavaScript). svgin-react fetches the SVG, sanitizes it, and inlines it as a normal React element.

For a static icon set that ships with your app, SVGR is the better fit; it works at build time with zero runtime cost. Reach for svgin-react when the SVG's content is not known until runtime: fetched from a URL, returned by an API, or stored in a database.

Install

npm install svgin-react

The default sanitizer needs DOMPurify, and on the server it also needs jsdom:

# client component only
npm install dompurify

# server component only
npm install dompurify jsdom

If you always pass your own sanitizeFn, or always use disableSanitization, you do not need either. They are optional peer dependencies, loaded lazily only when the default sanitizer actually runs.

Quick start

import { SvgIn } from 'svgin-react';

export default function AlertIcon() {
  return <SvgIn src="/icons/alert.svg" width={24} fill="#f00" />;
}

This one import works in both a client component and a server component. In a Next.js App Router file, add 'use client' at the top if you specifically want the client version.

To force one or the other:

import { SvgIn as SvgInClient } from 'svgin-react/client'; // client component
import { SvgIn as SvgInServer } from 'svgin-react/server'; // server component

Works with any React 19+ setup: Next.js (Pages Router and App Router), Remix, Vite + React, Create React App, Astro (React islands), and plain Node SSR.

More examples: raw markup, authenticated fetch, accessibility, custom sanitizer, callbacks, lazy loading

Raw markup you already have (from a CMS or API response), no fetch needed:

const { icon } = await cms.getContent(); // icon is a raw SVG string
<SvgIn svg={icon} width={24} />

Fetching from an authenticated endpoint:

<SvgIn src="/api/user-uploaded-icon" fetchOptions={{ headers: { Authorization: `Bearer ${token}` } }} />

Accessible name and description:

<SvgIn src="/icons/alert.svg" title="Alert" description="Indicates a warning that needs attention" />

Custom sanitizer, or skip sanitization for SVGs you trust completely:

<SvgIn src="/icons/alert.svg" sanitizeFn={async (svg) => svg} />
<SvgIn src="/icons/alert.svg" disableSanitization />

Error and mount callbacks:

<SvgIn
  src="/icons/alert.svg"
  onError={(error) => reportToTelemetry(error)}
  onMount={(svg) => svg.classList.add('ready')}
/>

Deferring the fetch until the icon scrolls near the viewport, for icon-heavy lists:

<SvgIn src="/icons/alert.svg" loading="lazy" />

Sharing defaults (className, fallback, onError, etc.) across many icons with <SvgInProvider>, and every other prop, are covered in docs/api.md.

Suspense: <SvgInSuspense /> suspends via React 19's use() instead of managing its own loading/error state
import { SvgInSuspense } from 'svgin-react/suspense';

<Suspense fallback={<IconSkeleton />}>
  <SvgInSuspense src="/icons/alert.svg" />
</Suspense>

Pair it with a <Suspense> boundary and an error boundary instead of fallback/loadingFallback. It does not automatically retry a failed src, see docs/advanced.md for why and how to force one. Full props in docs/api.md.

Shadow DOM: <SvgInShadow /> encapsulates the SVG's style in a shadow root, in both directions
import { SvgInShadow } from 'svgin-react/shadow';

<SvgInShadow src="/icons/alert.svg" styles="path { fill: red; }" />

Page CSS cannot reach in to affect the SVG, and the styles prop's CSS can never leak out onto the page. Use it when a source SVG's inline <style> block needs to stay scoped to that one instance, see docs/advanced.md for the limitation this solves. Full props in docs/api.md.

Preloading and cache utilities: warm the cache ahead of render, invalidate it on demand
import { clearSvgCache, hasCachedSvg, preloadSvg } from 'svgin-react/core';

await preloadSvg('/icons/alert.svg'); // fetches and caches ahead of render
hasCachedSvg('/icons/alert.svg');     // true, no fetch
clearSvgCache('/icons/alert.svg');    // forget one entry (or clearSvgCache() for all)

A later <SvgIn src={url} /> for the same URL resolves from the cache instead of fetching again. See docs/api.md for both, and docs/advanced.md for exactly which calls share the cache.

Choosing an entry point

Entry point Use for
svgin-react Auto-resolves to the server or client component depending on where it is imported.
svgin-react/client <SvgIn /> and <SvgInProvider>, forced client.
svgin-react/server <SvgIn />, forced server.
svgin-react/core preloadSvg, clearSvgCache, hasCachedSvg, no React component.
svgin-react/suspense <SvgInSuspense />.
svgin-react/shadow <SvgInShadow />.
svgin-react/all Every client + core export behind one import.

<SvgInSuspense /> and <SvgInShadow /> each have their own entry point so they cost nothing to consumers who do not use them. Full reasoning in docs/api.md.

Security

SVGs are sanitized with DOMPurify by default. Use your own sanitizeFn, or set disableSanitization, only for SVGs you fully trust. Published bundles carry npm provenance attestations. See SECURITY.md to report a vulnerability, and docs/advanced.md for the full threat model.

Documentation

  • docs/api.md: complete props and exports for every component and entry point.
  • docs/advanced.md: identity/caching semantics, reference-counted cancellation, Suspense retry behavior, the inline <style> scoping limitation, and a detailed comparison against react-svg, react-inlinesvg, and SVGR.

Development

See CONTRIBUTING.md for the local setup, required checks, and pull request conventions, and docs/maintainers.md for the release process.

Contributing

Bug reports, feature requests, and pull requests are welcome. See CONTRIBUTING.md to get started, and CODE_OF_CONDUCT.md for how we expect people to treat each other in this project.

Using an AI coding tool (Claude Code, Cursor, Copilot, Gemini, etc.) in this repo? See AGENTS.md for shared agent instructions. See llms.txt for a machine-readable summary of this package.

License

MIT, see LICENSE.

About

Fetch an SVG from a URL and render it as a real, styleable React element, sanitized by default, works in RSC and the browser.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages