How to use an SVG file in a SvgIcon in Material-UI

SvgMaterial Ui

Svg Problem Overview


I've got an SVG file and I want to make an SvgIcon component out of it, how should I do that?

In the documentation, all the examples use either predefined Material Icons or a strange notation of <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" /> which I have no idea what it is!

Svg Solutions


Solution 1 - Svg

1. Using <Icon/> component and an <img/> element

To use a SVG file as an icon, I used the <Icon/> component with an <img/> element inside, setting the height: 100% to the img element and textAlign: center to the root class of the <Icon/> component did the trick:

JSX:

import Icon from '@material-ui/core/Icon';
import { makeStyles } from '@material-ui/styles';
...

<Icon classes={{root: classes.iconRoot}}>
  <img className={classes.imageIcon} src="/graphics/firebase-logo.svg"/>
</Icon>

Styles:

const useStyles = makeStyles({
  imageIcon: {
    height: '100%'
  },
  iconRoot: {
    textAlign: 'center'
  }
});

Result:

Material UI Drawer Icon from SVG

UPDATE

As Lorenz Haase mentions in the comments, there is a slighly cuttting of the SVG at the bottom, which it can be fixed if we use flexbox and inherit width and height:

const useStyles = makeStyles({
  imageIcon: {
    display: 'flex',
    height: 'inherit',
    width: 'inherit'
  }
});

2. Using <SvgIcon/> component and @svgr/webpack webpack loader

According to the official MUI documentation, we can use <SvgIcon/> component props and have a @svgr/webpack loader to load .svg files using ESM imports.

> ## Component prop > > You can use the SvgIcon wrapper even if your icons are saved in the > .svg format. svgr has loaders to import SVG files and use them > as React components. For example, with webpack:

// webpack.config.js
{
  test: /\.svg$/,
  use: ['@svgr/webpack'],
}

// ---
import StarIcon from './star.svg';

<SvgIcon component={StarIcon} viewBox="0 0 600 476.6" />

> It's also possible to use it with "url-loader" or "file-loader". It's > the approach used by Create React App.

// webpack.config.js
{
  test: /\.svg$/,
  use: ['@svgr/webpack', 'url-loader'],
}

// ---
import { ReactComponent as StarIcon } from './star.svg';

<SvgIcon component={StarIcon} viewBox="0 0 600 476.6" />

Solution 2 - Svg

<path /> is an SVG path, i.e. the internal bits of the SVG. the SvgIcon component really should be able to take a path, but it doesn't :(

instead you can create a component like https://github.com/callemall/material-ui/blob/56c113217d7d05d8bb0712771b727df81984d04b/src/svg-icons/action/home.js

with your svg source in place of the path. (I recommend minifying it a bit using https://jakearchibald.github.io/svgomg/)

Solution 3 - Svg

You can import SVGs directly as React components and use them in <SvgIcon>:

import React from "react";
import { ReactComponent as Logo } from "./logo.svg";
import SvgIcon from "@material-ui/core/SvgIcon";

const App = () => (
  <SvgIcon>
    <Logo />
  </SvgIcon>
);

export default App;

See also: https://create-react-app.dev/docs/adding-images-fonts-and-files/#adding-svgs

Unfortunately React seems not able to render all kind of SVGs (e.g. modified with Inkscape, Illustrator) yet. But at least the default logo.svg inside a create-react-app project works.

Solution 4 - Svg

To obtain the path for SvgIcon, open svg file with the text editor and copy the corresponding path expression.

Solution 5 - Svg

The solution that worked for me is the following

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

 let smile = (props) => (
   <SvgIcon {...props} >
<path d="M256,32C132.281,32,32,132.281,32,256s100.281,224,224,224s224-100.281,224-224S379.719,32,256,32z M256,448
c-105.875,0-192-86.125-192-192S150.125,64,256,64s192,86.125,192,192S361.875,448,256,448z M160,192c0-26.5,14.313-48,32-48
s32,21.5,32,48c0,26.531-14.313,48-32,48S160,218.531,160,192z M288,192c0-26.5,14.313-48,32-48s32,21.5,32,48
c0,26.531-14.313,48-32,48S288,218.531,288,192z M384,288c-16.594,56.875-68.75,96-128,96c-59.266,0-111.406-39.125-128-96"/>
   </SvgIcon>
 );

 smile = pure(smile);
 smile.displayName = 'smile';     
 smile.muiName = 'SvgIcon';

 export default smile;

Check this example of material ui icon

Solution 6 - Svg

The SvgIcon is not meant for this purpose. More on this @ Github.

You are probably looking for this startIcon={<img src={google}></img>}

import google from "../../Assets/img/google.svg";
import GitHubIcon from "@material-ui/icons/GitHub";
const useStyles = makeStyles((theme) => ({
         root: {
                display: "flex",
                flexDirection: "column",
                margin: theme.spacing(1),
                },
          button: {
               margin: "0.5rem",
                  },
          googleStyle: {
                fillColor: theme.palette.primary.main,
                    },
              }));

export default function ContainedButtons() {
  const classes = useStyles();
   return (
  <div>
  <Button
    variant="contained"
    color="secondary"
    className={classes.button}
    startIcon={<img src={google}></img>}
  >
    Login With Google
  </Button>
  <Button
    variant="contained"
    color="secondary"
    className={classes.button}
    startIcon={<GitHubIcon />}
  >
    Login with GitHub
  </Button>
</div>
);
}

Solution 7 - Svg

If making more than one icon, you may not want to repeat all the boilerplate in the example referenced in the accepted answer. You can use a wrapper component generator like:

const wrapSvgPath = (path, viewBox='0 0 24 24') => (props) => (
    <SvgIcon {...props} viewBox={viewBox}>{path}</SvgIcon>
)

used like:

const facebookPath = (<path
        d="M17,2V2H17V6H15C14.31,6 14,6.81 14,7.5V10H14L17,10V14H14V22H10V14H7V10H10V6A4,4 0 0,1 14,2H17Z" />
)
export const FacebookIcon = wrapSvgPath(facebookPath)

Solution 8 - Svg

import SvgIcon from '@material-ui/core/SvgIcon'
import Register from "./../../media/register.svg"
import React from 'react';

const getSvgIconMaterial = (Icon: string, props?: any) => {
    return (
        <SvgIcon component="object">
            <embed type="image/svg+xml" src={Icon} style={{ height: "100%" }} />
        </SvgIcon>
    );
};

use like this

<>{getSvgIconMaterial(Register)}</>

Probably not perfect but works nicely. Maybe add a small padding/margin. React SVG Custom Component

Solution 9 - Svg

Open your svg file in a editor (example: vscode). You will see a file structure of something similar like this ->

<svg width="27" height="28" viewBox="0 0 27 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.91942 27.5138L6.15827 26.984L8.69599 21.1562H8.68852L13.5027 10.3812L18.3542 21.1562H18.3467L21.1083 27.5138H26.2509L15.8687 4.72523L13.5698 0L0.933594 27.5138H5.91942Z" fill="#A7A9AC"/>
</svg>

Then go to your react components, replace path with your own path. This should work. Add styles for custom change of design.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMehranView Question on Stackoverflow
Solution 1 - SvgChristos LytrasView Answer on Stackoverflow
Solution 2 - SvgGerbalView Answer on Stackoverflow
Solution 3 - SvgneumannView Answer on Stackoverflow
Solution 4 - SvgEugene TulikaView Answer on Stackoverflow
Solution 5 - SvgJorge SantosView Answer on Stackoverflow
Solution 6 - SvgAneesh PanoliView Answer on Stackoverflow
Solution 7 - SvgEd StaubView Answer on Stackoverflow
Solution 8 - Svgru4ertView Answer on Stackoverflow
Solution 9 - SvgSaikat halderView Answer on Stackoverflow