DEV Community

Cover image for Importing SVG files as React components with Vite
Cassidy Williams
Cassidy Williams

Posted on

Importing SVG files as React components with Vite

Chances are if you've ever used create-react-app and you wanted to import an SVG file as a React component, you did something like this and it Just Worked™:

import { ReactComponent as Logo } from './logo.svg'
Enter fullscreen mode Exit fullscreen mode

But, alas, if you have moved to using Vite more often, as I have, you can't just do that.

Never fear, it's still possible!

Enter vite-plugin-svgr

vite-plugin-svgr is a Vite plugin to transform SVGs into React components! It's super intuitive to use:

npm install vite-plugin-svgr
Enter fullscreen mode Exit fullscreen mode

Add it to your vite.config.js:

import svgr from 'vite-plugin-svgr'

export default {
  // ...
  plugins: [svgr()],
  // ...
}
Enter fullscreen mode Exit fullscreen mode

And boom, you get your expected behavior!

// somewhere in your React + Vite app

import { ReactComponent as WhateverIcon } from "./icons/WhateverIcon.svg";

// ...

export default function SomeComponent() {
    return (
        <div>
            <WhateverIcon />
            Wow, I love icons, because I am a dweeb
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

This is particularly useful if you're using a library like MUI and you need to use a custom icon, like so:

// somewhere in your React + Vite app

import { Box, IconButton, SvgIcon } from "@mui/material";
import { ReactComponent as WhateverIcon } from "./icons/WhateverIcon.svg";

// ...

export default function SomeComponent() {
    return (
        <Box>
            <IconButton aria-label="some icon">
                <SvgIcon>
                    <WhateverIcon />
                </SvgIcon>
            </IconButton>
            Wow, I love icons, because I am a dweeb
        </Box>
    );
}
Enter fullscreen mode Exit fullscreen mode

There's other things you can do with vite-plugin-svgr, and there's a list of options here.

Hope that's helpful for ya, happy icon-ing!

Top comments (14)

Collapse
 
cooty profile image
Cooty

Nice one, works like a charm. I only have one small problem / question. I'm using TypeScript (v4.9.3), Vite v4.2.0 and vite-plugin-svgr v2.4.0.

I import icon as shown above:

import { ReactComponent as SunnyIcon } from '../assets/icons/sunny.svg'
Enter fullscreen mode Exit fullscreen mode

I get a red underline for ReactComponent saying:

Module '"*.svg"' has no exported member 'ReactComponent'. Did you mean to use 'import ReactComponent from "*.svg"' instead?ts(2614)
Enter fullscreen mode Exit fullscreen mode

Of course if I use it as suggested, importing a default

import ReactComponent from '../assets/icons/sunny.svg'
Enter fullscreen mode Exit fullscreen mode

the TS error goes away, but can't use it as a React component since this way I just get the asset path as string.

The quick solution that I've found is to add a // @ts-ignore above it and move on with my life, but I wonder is there some way to get this working with TS?

Collapse
 
moussaabmoulim profile image
moussaab moulim
Collapse
 
christian_go3 profile image
Christian GO

Informative, thank you for sharing!

Collapse
 
danieljimenez0255 profile image
Daniel Jimenez

Thank you so much for this! A great breakdown as I was able to set up the fix using this in a few seconds! Awesome stuff

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Ok, serious question: I'm no Vite expert. I have only tested it a bit once. In the project, I have an SVG in the /assets folder, react.svg. It is imported from App.jsx:

import reactLogo from './assets/react.svg'

// Then used like this.
<img src={reactLogo} className="logo react" alt="React logo" />
Enter fullscreen mode Exit fullscreen mode

What's the difference in result between this and what you present? What is the gain?

Collapse
 
cassidoo profile image
Cassidy Williams

Long story short, by importing an SVG as a component, you can access the paths and objects in the component. If you use SVGs in <img> tags, you don't get to control the innards of the SVG with CSS etc!

Collapse
 
yeasin2002 profile image
Md Kawsar Islam Yeasin

If you use svgr then you don't need any Img tag.
basically, the svg will render in a img tag on the other hand if you use svgr then it will act like a native html svg elements. it's not like asserts that you have to load after the initial render.
It can render directly

Collapse
 
seromaxa profile image
Romanenko Serg

In your case reactLogo use like url, so you can't do some SVG tricks, you can transform only img.

Collapse
 
leosantosw profile image
Leo santos

This is interesting, Thank you!

Collapse
 
ahmadadibzad profile image
Ahmad Adibzad

If you are using vite-plugin-svgr version ^4.0.0 make sure to use the '?react' suffix on your SVG file address:

import Logo from './logo.svg?react'
Enter fullscreen mode Exit fullscreen mode

check out this:
stackoverflow.com/questions/70309561

Collapse
 
michaelindochat profile image
Michael Luo

How can I use svgr to import all the svg in the icons folder at once?

current progrewss

Hook

// hoos/useDynamicSvgImport.ts
import * as allIcons from '@/assets/images/icons';

export function useDynamicSvgImport(iconName: string) {
  const SvgIcon = allIcons[iconName] || null;

  return { SvgIcon };
}
Enter fullscreen mode Exit fullscreen mode

Component

// components/SvgIcon.tsx
import { useDynamicSvgImport } from "@/hooks/useDynamicSvgImport";

interface IProps {
  iconName: string;
  wrapperStyle?: string;
  svgProp?: React.SVGProps<SVGSVGElement>;
}

function SvgIcon(props: IProps) {
  const { iconName, wrapperStyle, svgProp } = props;
  const { SvgIcon: RawSvgIcon } = useDynamicSvgImport(iconName);

  return (
    <>
      {RawSvgIcon && (
        <i className={wrapperStyle}>
          <RawSvgIcon {...svgProp} />
        </i>
      )}
    </>
  );
}

export default SvgIcon;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
azariaberyl profile image
Azaria Beryl Nagata

I'm using React Icons and it works fine without this plugin. Have you tried it before?

Collapse
 
cassidoo profile image
Cassidy Williams

React Icons already exports SVGs as components. This is for your own custom SVG files that a designer might give to you, not from an existing library.

Collapse
 
azariaberyl profile image
Azaria Beryl Nagata • Edited

I see, that's why I never have problem with svg. Thanks