mrkeyoor.com_
Sun 20 Sept 11:46 UTC
npmWeb Frontendupdated 20 Sept 2026

@svgr/core review

@svgr/core 8.1.0 is the Node API for generating React component source from an SVG string. transform() passes source through an ordered plugin list and returns JavaScript or TypeScript text; it does not render SVG at application runtime. Version 8 core ships with no default plugins, so a caller must install and select @svgr/plugin-jsx, then optionally add SVGO or Prettier. The 8.1.0 release corrects configuration precedence, CLI defaults, and a React Native import, and adds svgo.config.cjs support. Our browser build failed because this 69-package toolchain is for build-time Node work.

Verdict

@svgr/core 8.1.0 took 5.8 seconds and 20 MB across 69 packages in our sandbox, and its browser build failed as expected for a Node generator. Install it only when you need a custom code-generation pipeline; use a CLI or bundler wrapper for ordinary SVG conversion.

We installed it

Lab card: what happened when we installed @svgr/coreScreenshot of @svgr/core documentation
Install✓ · 5.8s69 packages on disk · 20 MB
ImportESM import works · require() works · CommonJS package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @svgr/core install cleanly?

Yes. In a fresh container with an empty cache, npm install @svgr/core finished in 6 seconds, leaving 69 packages and 20 MB on disk. npm audit reported no known vulnerabilities.

Can @svgr/core run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does @svgr/core work with both ESM and CommonJS?

Yes. Both import '@svgr/core' and require('@svgr/core') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does @svgr/core include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@svgr/core or @svgr/cli: which should you use?

@svgr/cli: Choose it for file and directory conversion from a script without writing the transform and output loop yourself. @svgr/core 8.1.0 took 5.8 seconds and 20 MB across 69 packages in our sandbox, and its browser build failed as expected for a Node generator.

When should you not use @svgr/core?

Application code only imports SVG files through Vite or webpack; vite-plugin-svgr or @svgr/webpack already owns that integration point

API stability5/5The version 8 contract still consists of transform(source, config, state), transform.sync(), ordered plugins, and output options for TypeScript, exports, runtime, refs, titles, and templates. The absence of default plugins is the major migration point from older examples, not a recent change. With no release after 8.1.0, the API has little churn, although that also leaves new dependency combinations unproven by releases.
Docs4/5react-svgr.com separates the Node API, command line, webpack, Next.js, configuration files, SVGO, custom templates, React Native, and option reference. The package README explicitly says core has no plugins by default and shows the correct ordered list. Reproducible-build details such as disabling runtime config and choosing an output filename are documented less prominently than the transform call itself.
Maintenance2/5The registry's newest package is 8.1.0 from August 15, 2023. GitHub showed an unarchived repository pushed on March 1, 2026, with 148 open issues and pull requests, but no later package release. Repository edits alone do not demonstrate compatibility with current React, Babel, SVGO, or Prettier versions, so a team should pin the generator stack and test the emitted source.
Ecosystem5/5The npm downloads endpoint counted 17,922,000 installs from August 19 through August 25, 2026, and GitHub reported 11,055 stars. Core supports the official CLI and webpack package, while Vite has a published integration. Much of that volume is indirect through build tools, which supports the transform format without implying that every application needs to call the Node API itself.

Use it if

  • A design-system build script needs programmatic SVG-to-React generation outside a webpack or Vite loader
  • Generated icons require a custom Babel template, TypeScript output, ref forwarding, memo wrappers, or controlled exports
  • The repository commits generated components so SVG source changes and output diffs can be reviewed
  • One batch policy must normalize dimensions, currentColor, internal IDs, and accessible title behavior across many icons
Skip it if

Setup reality

We installed @svgr/core 8.1.0 in a fresh Node 22 sandbox in 5.8 seconds. It left 69 packages and 20 MB on disk. The core package declares five direct dependencies, no peer dependencies, and is 48 KB unpacked under MIT. npm audit reported zero known vulnerabilities. Bundled TypeScript declarations were present. CommonJS require() and ESM import both worked through the exports map. Our esbuild browser build failed on Node-only paths, which confirms this belongs in a generator or build process.

The first-run surprise is an empty plugin pipeline. Install @svgr/plugin-jsx and pass it in plugins or transform() will not turn the SVG into a React component. Add @svgr/plugin-svgo before JSX when optimization is wanted, and @svgr/plugin-prettier afterward when generated formatting belongs in SVGR. That means a useful setup exceeds the measured core install. Pin every plugin and snapshot output for gradients, masks, clip paths, titles, viewBox behavior, and React Native variants.

No credentials are required. With runtimeConfig enabled and state.filePath supplied, SVGR searches for .svgrrc files, config modules, or package settings and combines them with call options. Version 8.1.0 fixes command-line configuration precedence, which shows that source location can affect output. Set runtimeConfig: false when a reproducible generator must ignore the directory tree. The caller still owns component naming, extension selection, destination paths, and safe writes.

transform() is asynchronous; transform.sync() is available but cannot load asynchronous configuration or plugins. An uploaded SVG is active markup, so sanitize or reject external references and dangerous content before turning it into committed or served code. Preserve viewBox for scalable icons, prefix internal IDs to prevent collisions, and decide between title-based names and aria-hidden output. A 20 MB code generator should stay out of production browser dependencies and ordinary request paths.

Patterns

Run an explicit plugin pipeline transform-svg-to-jsx

import { transform } from '@svgr/core'
import { readFile, writeFile } from 'node:fs/promises'

const svg = await readFile('icons/check.svg', 'utf8')
const code = await transform(svg, {
  plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx', '@svgr/plugin-prettier'],
}, { componentName: 'CheckIcon' })
await writeFile('src/icons/CheckIcon.jsx', code)

Version 8 core has no default plugins. The list runs in order, so SVG optimization precedes JSX conversion and formatting comes last.

Ignore repository configuration make-deterministic-transform

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  runtimeConfig: false,
}, {
  componentName: 'Logo',
  filePath: 'assets/logo.svg',
})

runtimeConfig: false prevents .svgrrc and parent package settings from changing output based on file location.

Generate source synchronously run-synchronous-transform

import { transform } from '@svgr/core'

const code = transform.sync(svg, {
  plugins: ['@svgr/plugin-jsx'],
  runtimeConfig: false,
}, { componentName: 'CloseIcon' })

transform.sync() cannot consume asynchronous config or plugin setup; use the promise API unless the caller truly requires sync work.

Generate a typed ref component emit-typescript-component

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  typescript: true,
  ref: true,
  memo: true,
}, { componentName: 'SearchIcon' })

Write TypeScript output to a .tsx file, and verify the ref and memo wrappers before publishing the export contract.

Map designer colors to currentColor convert-fill-to-currentcolor

const code = await transform(svg, {
  plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
  icon: true,
  replaceAttrValues: {
    '#063855': 'currentColor',
    '#000000': 'currentColor',
  },
})

Replacement matches literal values. Normalize SVG color spellings or enumerate each source form that the icon pipeline accepts.

Keep scaling and isolate internal IDs preserve-viewbox-and-ids

const code = await transform(svg, {
  plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
  svgoConfig: {
    plugins: [
      { name: 'preset-default', params: { overrides: { removeViewBox: false } } },
      'prefixIds',
    ],
  },
})

viewBox enables CSS scaling, while prefixIds prevents gradients, masks, and clip paths from colliding between icons on one page.

Expose title and description props add-accessible-title

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  titleProp: true,
  descProp: true,
}, { componentName: 'StatusGraphic' })

Callers must supply meaningful title text for named graphics; decorative icons should instead use aria-hidden.

Generate hidden decorative output mark-icon-decorative

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  icon: true,
  svgProps: {
    focusable: 'false',
    'aria-hidden': 'true',
  },
})

aria-hidden removes the graphic from the accessibility tree, so do not use this policy for an icon that carries the only label.

Emit a named component export choose-named-export

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  exportType: 'named',
  namedExport: 'ReactComponent',
}, { componentName: 'Logo' })

Named and default exports create different consumer imports; settle the package convention before generating a public icon set.

Use the automatic JSX runtime select-jsx-runtime

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  jsxRuntime: 'automatic',
})

The consuming compiler must already support the automatic runtime; generated source cannot enable that setting itself.

Wrap output with a Babel template supply-custom-template

const template = (variables, { tpl }) => tpl`
${variables.imports};
${variables.interfaces};
const ${variables.componentName} = (${variables.props}) => ${variables.jsx};
${variables.exports};
`

const code = await transform(svg, {
  plugins: ['@svgr/plugin-jsx'],
  template,
})

Template variables contain Babel AST nodes. Use the supplied tpl helper and snapshot-test changes that can rewrite every generated file.

Convert an SVG directory batch-generate-tsx-icons

import { transform } from '@svgr/core'
import { readdir, readFile, writeFile } from 'node:fs/promises'
import path from 'node:path'

for (const file of (await readdir('svg')).filter(name => name.endsWith('.svg'))) {
  const svg = await readFile(path.join('svg', file), 'utf8')
  const componentName = toPascalCase(path.basename(file, '.svg'))
  const code = await transform(svg, {
    plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
    typescript: true,
    icon: true,
    runtimeConfig: false,
  }, { componentName, filePath: path.join('svg', file) })
  await writeFile(path.join('src/icons', `${componentName}.tsx`), code)
}

Create the destination first, reject unsafe filenames, and keep naming plus config deterministic so a clean run produces no unrelated diff.

Alternatives

PackageRegistryPick it when
@svgr/clinpmChoose it for file and directory conversion from a script without writing the transform and output loop yourself
@svgr/webpacknpmChoose it when webpack should turn imported SVG files into React components during bundling
vite-plugin-svgrnpmChoose it when a Vite application wants SVG component imports with SVGR options inside the build config

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.