202

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.

Srdjan Pazin
  • 103
  • 2
  • 5
Kamaraju
  • 2,365
  • 2
  • 15
  • 17

16 Answers16

430

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.

kelsny
  • 23,009
  • 3
  • 19
  • 48
Tsuni
  • 5,348
  • 2
  • 13
  • 20
  • 79
    Bear in mind that `ReactComponent` name is not optional. – Eduard Feb 05 '20 at 07:16
  • 4
    Also, note that the "fill" props are supported for the color change, but make sure default fill props are set with SVG like . – Jaison James Mar 02 '20 at 13:38
  • I like this way of implementation here as well you can find multiple ways https://blog.logrocket.com/how-to-use-svgs-in-react/ Thanks a lot @Tsuni – mustafa-elhelbawy May 15 '20 at 14:15
  • 6
    @Jaison I always set it to `fill="currentColor"` which allows you to style it in code. – Mordechai Sep 25 '20 at 01:32
  • I tried this method. the problem is that my svg is not shown correctly in mobile view. I don't know whether the problem is because of this line of code or not. – Shadi Farzankia Mar 12 '21 at 16:05
  • Does this way slow down the loading process? I find my svg icons loading slow even when they are stored locally – Yossi Sternlicht Apr 08 '21 at 13:05
  • 1
    @Mordechai after set fill="currentColor" in the svg path internal code, what worked for me was to use the regular color prop, not fill. . – Juanma Menendez May 17 '21 at 00:51
  • 9
    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.` – Jonathan Tuzman Oct 09 '21 at 16:16
  • 3
    this only works with create-react-app, cause it transpiles svg to react component otherwise you should probably use other solutions – Mateusz Apr 26 '22 at 10:23
  • 1
    @JonathanTuzman Did you try making sure that you have both the `ReactComponent as` and the new name starts with a capital letter? – sayandcode Sep 06 '22 at 06:45
99

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;
}
Hristo Eftimov
  • 13,845
  • 13
  • 50
  • 77
janhartmann
  • 14,713
  • 15
  • 82
  • 138
  • The second suggestion doesn't seem to work in Blink and Webkit. Works fine in Firefox though – Corey Bruyere Aug 30 '18 at 17:42
  • 1
    Interesting - i have another option I use today, which I can update next week. Out of office before. – janhartmann Aug 30 '18 at 17:43
  • @janhartmann - Hi, Can you please update the answer as you said? – vsync Sep 08 '18 at 15:45
  • what do you mean by icon "sprite"? Why can't it be addressed as svg? – Giridhar Karnik Apr 14 '19 at 15:37
  • 2
    You are using [SVG fragments](https://caniuse.com/#feat=svg-fragment) here without even mentioning this, which is critical to the answer. – vsync Jun 19 '19 at 09:39
  • Don't use `style="display: none"` like that to hide the icons SVG on the page. If your SVG contains gradients patterns etc, it may prevent them from rendering properly on some browsers. Use something like `width="0" height="0"` instead. – Paul LeBeau Jan 18 '20 at 20:49
  • How can I use the second way with webpack svg-url-loader? It will always base64 my svg and not show the icon. – digitalsuite.net Oct 25 '22 at 11:08
53

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>
Roman
  • 19,236
  • 15
  • 93
  • 97
  • 1
    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 :) – need_to_know_now Feb 12 '21 at 14:49
  • 1
    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. – Roman Feb 13 '21 at 16:37
  • 1
    Exactly what I needed to use the require function! – Lucas Perry Mar 24 '21 at 13:56
  • 1
    Thank you, this worked for me! – Ali Tarraf Feb 03 '22 at 20:21
  • 1
    Thank you, i read many articles and this is the only thing that worked! – mike gold Jun 15 '22 at 17:03
33

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.

Srinivas Damam
  • 2,893
  • 2
  • 17
  • 26
20

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;
Mohamed Jakkariya
  • 1,257
  • 1
  • 13
  • 16
19

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/

13

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

  ReactDOM.render(
      <img src={require("./svg/kiwi.svg")}/>,
      document.getElementById('root')
  );
theUtherSide
  • 3,338
  • 4
  • 36
  • 35
Hemadri Dasari
  • 32,666
  • 37
  • 119
  • 162
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

mattador
  • 421
  • 4
  • 12
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" />
SandroMarques
  • 6,070
  • 1
  • 41
  • 46
3

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}/>
Mayank
  • 3
  • 2
sana
  • 75
  • 6
3

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

pythonNovice
  • 1,130
  • 1
  • 14
  • 36
3

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"
/>
Ionut Enache
  • 461
  • 8
  • 22
  • Note: Next.js Image component with the default loader [doesn't support SSG](https://nextjs.org/docs/advanced-features/static-html-export#unsupported-features) through `next export`. – Alex Rintt Sep 23 '22 at 05:42
1

I am interesting to know how I can add the SVG as ReactComponent from a remote host, for example from CDN. I would use it as

http://URL/FILE.svg But this is not suitable for my use case.

I would like to see if I can use it as

import { ReactComponent as SvgIcon } from "http://URL/FILE.svg"

AJ-
  • 1,027
  • 2
  • 13
  • 24
1

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

Laura
  • 265
  • 2
  • 11
1
import SVG from './your-svg.svg';

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

const App = () => (
 <div>
   <img src={SVG} />
 </div>
);
Johnson Fashanu
  • 897
  • 8
  • 6
-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>
MustModify
  • 657
  • 10
  • 20