How to import SVG files as React Components in Vite App

Josh Praise
4 min readApr 3, 2024

--

I recently worked on a custom React.js and Vite.js setup where I needed to use SVG files within my code.

SVG stands for Scalable Vector Graphics. It’s an XML-based vector image format for two-dimensional graphics with support for interactivity and animation. SVG images are resolution-independent, which means they can be scaled to any size without losing quality.

In case you didn’t know, Vite is a build tool for modern web development that focuses on fast development and optimized builds. It is designed to work with modern JavaScript frameworks like Vue.js, React, and Svelte, although it can be used with vanilla JavaScript as well.

One of Vite’s key features is its ability to provide a fast development server with hot module replacement (HMR), enabling quick feedback loops during development. It achieves this speed by leveraging native ES module support in modern browsers, along with a highly optimized bundling process.

“Vite is arguably the fastest module-bundler in the JavaScript ecosystem at the moment.”

I decided to place my SVG files and other vectors in a separate folder and then import them when needed using the import declaration command.

For context, according to MDN web docs, the static import declaration is used to import read-only live bindings which are exported by another module.

In order to use the import declaration in a source file, the file must be interpreted by the runtime as a module. In HTML, this is done by adding type=”module” to the <script> tag. Modules are automatically interpreted in strict mode.

In a Node.js project, it is usually defined by adding “type”: “module”, in the package.json file to indicate that the project is using ECMAScript modules (ES modules) for its JavaScript code. This means you can use the import and export syntax for module loading instead of require() and module.exports.

Having done it this way a million times, usually through Create React App (CRA), I thought it was going to be business as usual. But my joy was short lived when I encountered an error after I tried importing a SVG file as an icon within my component. Oh no! 😱

SVG import module declaration
SVG import module failure

Then I resorted to debugging the problem and find a solution. My gut feeling signaled to me that it’s got something to do with how my bundler (Vite) interpreted the SVG file but I needed to double check.

After a bit of research, I found out I could use a plugin called vite-plugin-svgr to handle SVG file interpretation since this feature doesn’t come with React or Vite out of the box. The SVGR Vite plugin basically transforms SVGs into React components.

By the way, Vite is also highly extensible via its Plugin API and JavaScript API.

Installation…

Please note the vite-plugin-svgr version installed on my app was version “4.2.0”: vite-plugin-svgr@4

Install vite-plugin-svgr by running any the following command:

# npm
npm install --save-dev vite-plugin-svgr

# yarn
yarn add -D vite-plugin-svgr

# pnpm
pnpm add -D vite-plugin-svgr

Setup your vite.config.js file in your root directory this way.

// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";

export default defineConfig({
// …
plugins: [ react(), svgr()],
});

The plugin’s guide suggests to add the “?react” suffix to each SVG import so the file is imported as a React component. E.g.

import Logo from "./logo.svg?react";

But…

I didn’t like this approach because one might forget to add the suffix during imports at some point in future and if you’d agree with me it’s also quite a monotonous process.

Say your project gets bigger over time and you’ve got new/more people collaborating with you who didn’t have prior knowledge of how the SVGs import works, they’d most likely run into the same problems and spend crucial dev time trying to find a solution if they had forgotten to add the suffix at the end of each import.

Also, you might have forgotten to pre-inform them that the suffix is needed to import SVGs as React components successfully.

Here’s the good stuff…

Since "vite-plugin-svgr" has got the react-svgr package under the hood. I applied some custom modification to the SVGR plugin options so I could import SVG files as React components without the “?react” suffix https://react-svgr.com/docs/options/

// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";

// https://vitejs.dev/config/
export default defineConfig({
// …
plugins: [
react(),
svgr({
// svgr options: https://react-svgr.com/docs/options/
svgrOptions: { exportType: "default", ref: true, svgo: false, titleProp: true },
include: "**/*.svg",
}),
],
});

Now you should be able to import SVGs without the ?react suffix. Just make sure your imported SVG file name is the same as the corresponding component. E.g.

import Logo from "./logo.svg";

const App = () => (
<div>
<Logo />
</div>
)

…and that does the trick!

Hope this piece was helpful to you.

PS. If you are using CRA, an alternative plugin you can use to import SVGs as React Component is @svgr/webpack — https://www.npmjs.com/package/@svgr/webpack

Other References:

--

--

Josh Praise

Josh is a disruptive Frontend Web Developer doing amazing stuff with JavaScript and modern Frontend frameworks to save the planet.