Use custom SVG file with MUI (material-ui) Icon Component?
Asked Answered
H

9

10

In my project, I am using custom svg files as part of the requirement. I am using [email protected] to achieve this. I looked at the example that is available on the official documentation -> https://material-ui.com/style/icons/#svg-icons

However, in my version, the custom icons do not appear the same way. My forked version is available at https://codesandbox.io/s/mqnq9qrqn8

What I am looking for is a way to use the custom icons that can work well with Material-UI's <Icon> Component.

Could someone please help me with this? Thank you

Heliozoan answered 18/4, 2019 at 21:39 Comment(1)
linked - https://mcmap.net/q/1160806/-use-svgr-and-material-ui-together/104380Provocative
M
17

You can also use the Material-UI IconButton component and wrap it around your svg img as shown below

import React from 'react'
import { Icon } from "@material-ui/core";
import YourLogo from './yourlogo.svg'

export const Logo = () => (
    <Icon>
        <img src={YourLogo} height={25} width={25}/>
    </Icon>
)
Muscatel answered 5/11, 2019 at 15:14 Comment(1)
Note: you have to specify the height and width or the svg will not appear. Thanks for the answer!Isocyanide
B
9

You can import the svg file as a React Component and then use it directly inside an SvgIcon Component from Material UI. This will also allow you to style your component.

import React from 'react';
import { SvgIcon, makeStyles } from '@material-ui/core';
import { ReactComponent as MySvg } from './img/someSvgFile.svg';

const useStyles = makeStyles(theme => {
  mySvgStyle:{
    fillColor: theme.palette.primary.main
  }
})

function MySvgIcon() {

  classes = useStyles();

  return(
    <SvgIcon className={classes.mySvgStyle}>
      <MySvg/>
    </SvgIcon>
  )
}
Boxcar answered 31/3, 2020 at 14:39 Comment(1)
This method throws an error in more recent years: Module '".svg"' has no exported member 'ReactComponent'. Did you mean to use 'import ReactComponent from ".svg"' instead? ts(2614)Busty
L
5

The answer lies in the viewBox attribute ( MDN )

When you are messing with SVGs, especially copy/pasted ones, you have to finesse the viewBox to frame your paths correctly. I usually start with <svg viewBox="0 0 100 100" /> and scale up or down, to taste. After some fiddling, "0 0 60 50" looks pretty good (link).

tags

Looking at the MaterialUI docs (link), they planned for this sort of thing and allow it as a prop on the component.

Lang answered 18/4, 2019 at 23:29 Comment(2)
Thank you so very much. I wonder how can I get then in viewBox 0 0 24 24Heliozoan
No problem. To change the size of the icon, you can just use the CSS properties, width and height. You could also add the attributes directly to <SVGIcon />. I updated the CodeSandbox to demonstrate (demo.js line 17). It's tricky for me to explain, but the way I think about viewBox is that it handles centering the paths within the SVG.Lang
D
1

just put an <img/> inside your <Icon/> or any other widgets...

import { Icon } from "@material-ui/core"
import YourImage from './yourImage.png'
                                       
export const YourComponent = () => (
    <Icon>
        <img src={YourImage}/>
    </Icon>
)
Disjunct answered 12/4, 2022 at 19:23 Comment(0)
S
1

You could use the createSvgIcon utility from MUI to create custom svg icons. It can be used to wrap an svg or an svg path, which is passed as a child to the SvgIcon component:

For example:

const HomeIcon = createSvgIcon(
  <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />,
  'Home',
);

For more information, check out this link.

Sholokhov answered 17/2, 2024 at 12:28 Comment(0)
G
0

This worked for me - an img tag inside a fragment:

import eraserIcon from "assets/svg/eraser.svg";
.
.
.
    <FormControlLabel
      value="female"
      control={
        <Radio
          value="sdfsdf"
          size="small"
          checkedIcon={
            <>
              <img alt="sd" src={eraserIcon} />
            </>
          }
          name="radio-buttons"
          inputProps={{ "aria-label": "B" }}
        />
      }
      label={"my-label"}
    />

inside the checkedIcon attribute that accepts a React.ReactNode.

I must say that aapa320's solution and Dinesh Nadimpalli's solution are much more elegant and flexible but I've tried them and the svg was no longer in the center, and its size changed.. so I had to do some extra work with it. My solution is very simple but it is limited, use it only if you don't have to provide custom CSS.

Gown answered 6/7, 2023 at 9:36 Comment(0)
G
0

What worked for me (I use js, not jsx but jsx should be similar I gues)

// add webpack loader for svg files
moduleLoaders.push({
    test: /\.svg$/,
    exclude: /node_modules/,
    use: {
        loader: 'svg-react-loader',
    },
})

...

import React from "react";
import createSvgIcon from "@mui/material/utils/createSvgIcon";

function MenuLogo(logo, text, props) {
    return React.createElement(createSvgIcon(
        React.createElement(logo, null)
    , text), props)
}

// where logo is something like:
import logo from "path/to/logo.svg"

// and props is just whatever you'd like to pass through material UI, eg. {sx: ...}
Geiss answered 4/9, 2023 at 10:13 Comment(0)
P
0

Below is a full solution for a React project with vite & svgr:

# npm
npm install --save-dev vite-plugin-svgr

# yarn
yarn add -D vite-plugin-svgr

# pnpm
pnpm add -D vite-plugin-svgr

Create an svgr template file named svg-template.js in your root folder, where vote.config file is at and configure your Vite like so:

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
import svgTemplate from "./svg-template";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");

  return {
    plugins: [
      react(),
      svgr({
        include: "**/*.svg",  // allows importing any `svg` file as a React component
        svgrOptions: {
          template: svgTemplate, // loads the custom svgr template
        },
      }),
    ],

  ...

svg-template.js:

The aim of the below svgr template is to wrap the imported svg file with MUI (test on v5) SvgIcon component so the end result will encapsulate the custom icon within a MUI icon component with all the inherited classes.

// svg-template.js
// https://mcmap.net/q/1040774/-use-custom-svg-file-with-mui-material-ui-icon-component
export default function SvgTemplate(
  { imports, interfaces, componentName, props, jsx, exports },
  { tpl }
) {
  return tpl`
import SvgIcon from '@mui/material/SvgIcon';
${imports}

${interfaces}

const ${componentName} = (${props}) => {
  return React.createElement(SvgIcon, props, ${jsx.children})
}

${exports}
  `;
}

then to use a custom Icon in your React code, simply import an SVG file and use as a compoonent:

import MyIcon from "icons/MyIcon.svg";

const App = () => (
  <MyIcon />
)

💡 I advise placing all your icons in one single folder and create an absolute path in your jsconfig file & bundler's configuration, for easier imports.

References:

Provocative answered 20/5, 2024 at 10:8 Comment(0)
B
0

@vsync Unfortunately the svgrOptions.template doesn't work for me. I don't get any errors either.

So here is my solution with svgr:

1) Allows importing any svg file as a React component

...
plugins: [
  react(),
  svgr({
    include: '**/*.svg'
  })
],
...

2) Use MUI-SvgIcon as wrapper

import SvgIcon from "@mui/material/SvgIcon";
import SmartToyTwoToneIconSvg from 'mui-material-icons/smart_toy_two_tone_24px.svg

<SvgIcon>
  <SmartToyTwoToneIconSvg />
</SvgIcon>

3) Download the required SVG icons from GitHub with cURL

curl -O --output-dir mui-material-icons/ https://raw.githubusercontent.com/mui/material-ui/next/packages/mui-icons-material/material-icons/cancel_24px.svg
Bromine answered 6/8, 2024 at 13:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.