How to use an SVG file in a SvgIcon in Material-UI
SvgMaterial UiSvg 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
<Icon/>
component and an <img/>
element
1. Using 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:
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'
}
});
<SvgIcon/>
component and @svgr/webpack
webpack loader
2. Using 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;
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.
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.