230

I have seen a lot of libraries for svg on react but none gave me how to import an svg file in the react component. I have seen code which talk about bring the svg code into react rather than using the .svg icon as image and show it in the UI.

Please let me know if there are ways to embed the icon.

18 Answers 18

481
+250

If you use create-react-app 2.0 you can now do it like this:

import { ReactComponent as YourSvg } from './your-svg.svg';

And then use it just like you would normally use a component:

const App = () => (
 <div>
   <YourSvg />
 </div>
);

Note that the new name must be capitalized, or else React won't recognize it as a component.

Sign up to request clarification or add additional context in comments.

11 Comments

Bear in mind that ReactComponent name is not optional.
Also, note that the "fill" props are supported for the color change, but make sure default fill props are set with SVG like <svg fill="#000">.
@Jaison I always set it to fill="currentColor" which allows you to style it in code.
Hm, straight up doesn't work for me. Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
this only works with create-react-app, cause it transpiles svg to react component otherwise you should probably use other solutions
|
109

There are two ways I want to show you.

The first one is just a simple import of the required SVG.

import MyImageSvg from '../../path/to.svg';

Just remember to use a loader for e.g. Webpack:

 {
     test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
     include: [Path.join(__dirname, "src/assets")],
     loader: "file-loader?name=assets/[name].[ext]"
 }

Another (and more elegant way) is that you can define an SVG icon sprite and use a component to fetch the correct sprite of the SVG. For example:

import React from "react";
import Icons from "../../assets/icons/icons.svg"; // Path to your icons.svg
import PropTypes from 'prop-types';

const Icon = ({ name, color, size }) => (
  <svg className={`icon icon-${name}`} fill={color} width={size} height={size}>
    <use xlinkHref={`${Icons}#icon-${name}`} />
  </svg>
);

Icon.propTypes = {
  name: PropTypes.string.isRequired,
  color: PropTypes.string,
  size: PropTypes.number
};

export default Icon;

The icon sprite (icons.svg) can be defined as:

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">

    <symbol id="icon-account-group" viewBox="0 0 512 512">
      <path d="m256 301l0-41c7-7 19-24 21-60 10-5 16-16 16-30 0-12-4-22-12-28 7-13 18-37 12-60-7-28-48-39-81-39-29 0-65 8-77 30-12-1-20 2-26 9-15 16-8 46-4 62 1 2 2 4 2 5l0 42c0 41 24 63 42 71l0 39c-8 3-17 7-26 10-56 20-104 37-112 64-11 31-11 102-11 105 0 6 5 11 11 11l384 0c6 0 10-5 10-11 0-3 0-74-10-105-11-31-69-48-139-74z m-235 168c1-20 3-66 10-88 5-16 57-35 99-50 12-4 23-8 34-12 4-2 7-6 7-10l0-54c0-4-3-9-8-10-1 0-35-12-35-54l0-42c0-3-1-5-2-11-2-8-9-34-2-41 3-4 11-3 15-2 6 1 11-2 13-8 3-13 29-22 60-22 31 0 57 9 60 22 5 17-6 37-11 48-3 6-5 10-5 14 0 5 5 10 11 10 3 0 5 6 5 11 0 4-2 11-5 11-6 0-11 4-11 10 0 43-16 55-16 55-3 2-5 6-5 9l0 54c0 4 2 8 7 10 51 19 125 41 132 62 8 22 9 68 10 88l-363 0z m480-94c-8-25-49-51-138-84l0-20c7-7 19-25 21-61 4-2 7-5 10-9 4-5 6-13 6-20 0-13-5-23-13-28 7-15 19-41 13-64-4-15-21-31-40-39-19-7-38-6-54 5-5 3-6 10-3 15 3 4 10 6 15 3 12-9 25-6 34-3 15 6 25 18 27 24 4 17-6 40-12 52-3 6-4 10-4 13 0 3 1 6 3 8 2 2 4 3 7 3 4 0 6 6 6 11 0 3-1 6-3 8-1 2-2 2-3 2-6 0-10 5-10 11 0 43-17 55-17 55-3 2-5 5-5 9l0 32c0 4 3 8 7 10 83 31 127 56 133 73 7 22 9 68 10 88l-43 0c-6 0-11 5-11 11 0 6 5 11 11 11l53 0c6 0 11-5 11-11 0-3 0-74-11-105z"/>
    </symbol>

    <symbol id="icon-arrow-down" viewBox="0 0 512 512">
      <path d="m508 109c-4-4-11-3-15 1l-237 269-237-269c-4-4-11-5-15-1-5 4-5 11-1 15l245 278c2 2 5 3 8 3 3 0 6-1 8-3l245-278c4-4 4-11-1-15z"/>
    </symbol>

    <symbol id="icon-arrow-left" viewBox="0 0 512 512">
      <path d="m133 256l269-237c4-4 5-11 1-15-4-5-11-5-15-1l-278 245c-2 2-3 5-3 8 0 3 1 6 3 8l278 245c2 2 4 3 7 3 3 0 6-1 8-4 4-4 3-11-1-15z"/>
    </symbol>

    <symbol id="icon-arrow-right" viewBox="0 0 512 512">
      <path d="m402 248l-278-245c-4-4-11-4-15 1-4 4-3 11 1 15l269 237-269 237c-4 4-5 11-1 15 2 3 5 4 8 4 3 0 5-1 7-3l278-245c2-2 3-5 3-8 0-3-1-6-3-8z"/>
    </symbol>
</svg>

You can define your own icon sprite on http://fontastic.me/ for free.

And the usage: <Icon name="arrow-down" color="#FFFFFF" size={35} />

And possible add some simple styling for using the icons everywhere:

[class^="icon-"], [class*=" icon-"] {
    display: inline-block;
    vertical-align: middle;
}

8 Comments

The second suggestion doesn't seem to work in Blink and Webkit. Works fine in Firefox though
Interesting - i have another option I use today, which I can update next week. Out of office before.
@janhartmann - Hi, Can you please update the answer as you said?
what do you mean by icon "sprite"? Why can't it be addressed as svg?
You are using SVG fragments here without even mentioning this, which is critical to the answer.
|
61

For some reasons above mentioned approaches did not work for me, before I followed the advice to add .default like this:

<div>
  <img src={require('../../mySvgImage.svg').default} alt='mySvgImage' />
</div>

5 Comments

Oh man thank you so much for this. The other answers didn't work for me either. Upon adding ".defaut" it worked. Might I ask you how you figured this out? And if you could link a relevant source so I could also understand why this works :)
Thanks for "thank you". I got the idea of the answer indirectly from answers to related questions. So I can not provider you with a link to the documentation. I guess you need to check a specification for the new ".require" version.
Exactly what I needed to use the require function!
Thank you, i read many articles and this is the only thing that worked!
Could you please explain how it works that way? I am new to this, so I didn't get it.
38

You can directly use .svg extension with img tag if the image is remotely hosted.

ReactDOM.render(
  <img src={"http://s.cdpn.io/3/kiwi.svg"}/>,
  document.getElementById('root')
);

Here is the fiddle: http://codepen.io/srinivasdamam-1471688843/pen/ZLNYdy?editors=0110

Note: If you are using any web app bundlers (like Webpack) you need to have related file loader.

8 Comments

I tried do that i dont see the image being displayed, i have local icon
When you say biolerplate what do you mean , i have the image in the same folder so i have something like src={"./abc.icon"}
If you have a local image and using webpack then you need to add file loader as a plugin to your webpack build config.
but it will add it with img tag, it won't have properties of svg
@SrinivasDamam how can we loop if we have 50+ svg files and where we have to store in public or src ?
|
21

Here I found a simple solution without ejecting and we don't need to install other dependencies like react-app-rewired. Because If you want to use SVG as a component we need to update the webpack config of create-react-app.

Method 1:

import { ReactComponent as YourSvg } from './your-svg.svg';

const App = () => (
 <div>
   <YourSvg />
 </div>
);

We can do it like this but it's only on create-react-app-2.0 as per the above answer.

Method 2:

We need to update the webpack configuration of create-react-app.

  1. Go to node_modules/react-scripts/config/webpack.config.js.
  2. Go to the line number 600.

Note:Here you'll see the following info

            // "file" loader makes sure those assets get served by WebpackDevServer.
            // When you `import` an asset, you get its (virtual) filename.
            // In production, they would get copied to the `build` folder.
            // This loader doesn't use a "test" so it will catch all modules
            // that fall through the other loaders.
            {
              loader: require.resolve('file-loader'),
              // Exclude `js` files to keep "css" loader working as it injects
              // its runtime that would otherwise be processed through "file" loader.
              // Also exclude `html` and `json` extensions so they get processed
              // by webpacks internal loaders.
              exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
              options: {
                name: 'static/media/[name].[hash:8].[ext]',
              },
            },
            // ** STOP ** Are you adding a new loader?
            // Make sure to add the new loader(s) before the "file" loader.
  1. Add the following line to the above file-loader.
         // #1 Custom loader for handling svg images 
            {
              test: /\.svg$/,
              use: ['@svgr/webpack']
            },

That's it 🎉🎉

How to use SVG inside react component?

import ChevronRight from '../../../assets/icons/feather/chevron-right.svg';

const Links = () => {
  return (
          <ChevronRight height={25} width={25} />    
      );
};

export default Links;

1 Comment

Note, that this solution requires Webpack.
20

if you have .svg or an image locally. first you have to install the loader needed for svg and file-loader for images. Then you have to import your icon or image first for example:

import logo from './logos/myLogo.svg' ;
import image from './images/myimage.png';

const temp = (
     <div>
         <img src={logo} />
         <img src={image} />
     </div>
);

ReactDOM.render(temp,document.getElementByID("app"));

Happy Coding :")

resources from react website and worked for me after many searches: https://create-react-app.dev/docs/adding-images-fonts-and-files/

3 Comments

Thanks, by far, the most convinient method - you have all the attributes - height, width and so on.
Worked for me (not like the other answers). Thanks! (And I'm using create-react-app.)
this is the best method, works in generally all environments, regardless of how React project is setup
13

You can also import .svg, .jpg, .png, .ttf, etc. files like:

  ReactDOM.render(
      <img src={require("./svg/kiwi.svg")}/>,
      document.getElementById('root')
  );

2 Comments

Much cleaner imo than using a component! :)
FWIW -- this didn't work for me without using the .default attribute described by @roman above.
6

Hard to believe adding a custom icon is so complicated. I found a similar solution to those posted above, but for me, I could not get the icon to display until I added the viewBox info, which I got directly from opening the SVG in a text editor.

//customIcon.js

import React from "react";
import {ReactComponent as ImportedSVG} from "path/to/myIcon.svg";
import { SvgIcon } from '@material-ui/core';

function CustomIcon() {
 return(
  <SvgIcon component={ImportedSVG} viewBox="0 0 384 512"/>

)
}

export default CustomIcon;

I also ran into an error with namespaces and had to clean up the SVG before it would work, following advice from this post

Comments

5

If you want to use SVG files as React components to perform customizations and do not use create-react-app, do the following:

  1. Install the Webpack loader called svgr
yarn add --dev @svgr/webpack
  1. Update your webpack.config.js
  ...
  module: {
    rules: [
      ...
      // SVG loader
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      }
    ],
  },
  ...
  1. Import SVG files as React component
import SomeImage from 'path/to/image.svg'

...

<SomeImage width={100} height={50} fill="pink" stroke="#0066ff" />

Comments

5

As additional info, if you are using NextJs, the easiest way to display a SVG is by importing your SVG and then using the <Image /> NextJs component:

import Image from 'next/image';
import SVGIcon from 'your/svg/path/icon.svg';

<Image
  src={SVGIcon}
  alt="Logo - SVG"
  width="40"
  height="40"
/>

2 Comments

Note: Next.js Image component with the default loader doesn't support SSG through next export.
unnecessary complexity -- easier to achieve with the component FC declaration, with the sgv body as content
4

Just write require with path inside the src of image. it will work. like:

<img alt="Clock" src={require('../assets/images/search_icon.svg').default}/>

Comments

3

You can turn your SVGs to a viable React Component through this site

Comments

2

If you have Material UI library in your React project, you can do the follow:

import React from 'react';
import { SvgIcon } from '@material-ui/core';

export function NewIcon() {
  return (
    <SvgIcon viewBox="0 0 48 48"> // you may change the viewBox, so the image will fit into it
      <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />
    </SvgIcon>
  )
}

This will automatically change the SVG color when the Theme is changed (Light/Dark). Plus you can change its color and size as you wish e.g.

import React from 'react';
import { styled, SvgIcon } from '@material-ui/core';

const SvgImage = styled(SvgIcon)(() => ({
  height: '40px',
  width: '40px',
  color: 'red',
}));

export function NewIcon() {
  return (
    <SvgImage viewBox="0 0 48 48">
      <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />
    </SvgImage>
  );
}

Documentation: https://mui.com/components/icons/#svgicon

Comments

2
import SVG from './your-svg.svg';

And then use it as the source in an image element:

const App = () => (
 <div>
   <img src={SVG} />
 </div>
);

Comments

1

Just make a component out of the svg file;

export const Spinner = () => {
    return (
        <svg width="24" height="24" stroke="#000" viewBox="0 0 24 24"
            xmlns="http://www.w3.org/2000/svg"><g><circle cx="12" cy="12" r="9.5" fill="none"
                strokeWidth="3" strokeLinecap="round"></g></svg>
    );
};

Save it as Spinner.tsx. And use it where its needed;

import { Spinner } from '../assets/Spinner';
...
...
<Spinner />

Comments

1

If you are using vite & react , use vite-plugin-svgr.

  1. Install plugin: yarn add -D vite-plugin-svgr

  2. Add this in the plugins array of vite.config.ts plugins: [svgr()],

  3. Import the svg in your component :import Logo from "./logo.svg?react"; keep in mind the ?react part.

  4. Add this in your vite-env.d.ts to get rid of type error /// <reference types="vite-plugin-svgr/client" />

Refer this link for more information: http://github.com/pd4d10/vite-plugin-svgr?tab=readme-ov-file#usage

Comments

0

At first, I used the importing an svg image as a ReactComponent and it worked. However, I bumped into an issue while running tests using Jest and react testing library. I was required to mock the icons which wasn't ideal and even after mocking, I still encountered some errors (check render method of the component error - encountered while testing components with the svg imports)

import {ReactComponent as ImportedSVG} from "path/to/myIcon.svg";

Akshay's response is closest to my implementation with the addition of the stroke prop which allows the icon to be reused, say you want the icon to have different colours in different components. You can do the same with other properties e.g fill, width, height etc

import React from "react";
import PropTypes from "prop-types";

const DeleteIcon = ({ stroke }) => {
  return (
    <svg
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke={stroke}
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M16 6V5.2C16 4.0799 16 3.51984 15.782 3.09202C15.5903 2.71569 15.2843 2.40973 14.908 2.21799C14.4802 2 13.9201 2 12.8 2H11.2C10.0799 2 9.51984 2 9.09202 2.21799C8.71569 2.40973 8.40973 2.71569 8.21799 3.09202C8 3.51984 8 4.0799 8 5.2V6M10 11.5V16.5M14 11.5V16.5M3 6H21M19 6V17.2C19 18.8802 19 19.7202 18.673 20.362C18.3854 20.9265 17.9265 21.3854 17.362 21.673C16.7202 22 15.8802 22 14.2 22H9.8C8.11984 22 7.27976 22 6.63803 21.673C6.07354 21.3854 5.6146 20.9265 5.32698 20.362C5 19.7202 5 18.8802 5 17.2V6"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
};

DeleteIcon.propTypes = {
  stroke: PropTypes.string,
};

DeleteIcon.defaultProps = {
  stroke: "",
};

export default DeleteIcon;

Example usage

import DeleteIcon from "../../assets/icons-js-files/delete-icon";

<DeleteIcon stroke="#ff2a58"/>

1 Comment

The 1st code snippet is no longer compatible with React 19, in combination with latest changes of the testing library. The 2nd one is the way to go.
-1

If your SVG includes sprites, here's a component you can use. We have three or four groups of sprites... obviously you can pull that bit out if you only have one sprite file.

The Sprite component:

import React from 'react'
import PropTypes from 'prop-types';

export default class Sprite extends React.Component {
  static propTypes = {
    label: PropTypes.string,
    group: PropTypes.string,
    sprite: PropTypes.string.isRequired
  }

  filepath(spriteGroup)
  {
    if(spriteGroup == undefined) {  spriteGroup = 'base' }
    return "/asset_path/sprite_" + spriteGroup + ".svg";
  }

  render()
  {
    return(
      <svg aria-hidden="true" title={this.props.label}>
        <use xlinkHref={`${this.filepath(this.props.group)}#${this.props.sprite}`}></use>
      </svg>
    )
  }
}

And elsewhere in React you would:

import Sprite from './Sprite';

render()
{
   ...
   <Sprite label="No Current Value" group='base' sprite='clock' />
}

Example from our 'base' sprite file, sprite_base.svg:

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="clock" viewBox="0 0 512 512">
      <path fill="currentColor" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm216 248c0 118.7-96.1 216-216 216-118.7 0-216-96.1-216-216 0-118.7 96.1-216 216-216 118.7 0 216 96.1 216 216zm-148.9 88.3l-81.2-59c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h14c6.6 0 12 5.4 12 12v146.3l70.5 51.3c5.4 3.9 6.5 11.4 2.6 16.8l-8.2 11.3c-3.9 5.3-11.4 6.5-16.8 2.6z" class="">
      </path>
    </symbol>
    <symbol id="arrow-up" viewBox="0 0 16 16">
      <polygon points="1.3,6.7 2.7,8.1 7,3.8 7,16 9,16 9,3.8 13.3,8.1 14.7,6.7 8,0 "> </polygon>
    </symbol>
    <symbol id="arrow-down" viewBox="0 0 16 16">
      <polygon points="14.7,9.3 13.3,7.9 9,12.2 9,0 7,0 7,12.2 2.7,7.9 1.3,9.3 8,16 "> </polygon>
    </symbol>
    <symbol id="download" viewBox="0 0 48 48">
      <line data-cap="butt" fill="none" stroke-width="3" stroke-miterlimit="10" x1="24" y1="3" x2="24" y2="36" stroke-linejoin="miter" stroke-linecap="butt"></line>
      <polyline fill="none" stroke-width="3" stroke-linecap="square" stroke-miterlimit="10" points="11,23 24,36 37,23 " stroke-linejoin="miter"></polyline>
      <line data-color="color-2" fill="none" stroke-width="3" stroke-linecap="square" stroke-miterlimit="10" x1="2" y1="45" x2="46" y2="45" stroke-linejoin="miter"></line>
    </symbol>
  </devs>
</svg>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.