How to render an SVG on the DOM in react 18? - reactjs

I have seen so many people discussing stuff that doesn't work all the times.
I am using react 18. I want to import an SVG file on my disk and render it on my DOM.
I tried to import it as:
import { ReactComponent as Underconstruction } from '../../media/business/under-construction.svg';
const Sidebar= ()=> {
return <Underconstruction />
}
But it showed me this error:
I have also tried to use it as a regular image tag and it showed me the same error:
const Sidebar= ()=> {
return <img src={require('../../media/business/under-construction.svg')} />
}
and I have tried to use require() but it showed 404 couldn't find the file:
const Sidebar= ()=> {
return <img src="../../media/business/under-construction.svg" />
}
I am using create-react-app
I am using react 18.
20 Oct 2022.

The easiest way to use your svg as a React component. So you do not need to care about the config
import React from 'react'
export function YourFileName() {
return (
<svg
...
>
<path
...
...
/>
</svg>
)
}
You can get svg tag by open svg by your code editor like vscode

Here are a couple of options for importing SVG into React:
Importing SVG in react as an image tag
Import SVG in react as JSX
Importing SVG as react component (Inline SVGs)
Importing SVGs in React Image Tag
import myLogo from '/path/to/image.svg'
const Button = () => {
return (
<button>
<img src={myLogo} alt="SVG logo image"/>
</button>
);
}
Importing SVG in React as JSX
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
Importing SVGs as React Component
export const LeftArrow = () =>{
return(
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
/>
</svg>
)
}
Now, you can import and render the react SVG component in another component like this:
import { LeftArrow } from './path/to/LeftArrow.jsx'
export const Button = () =>{
return(
<button>
<LeftArrow />
</button>
)
}

The easiest way is putting your svg in public folder like this
Then you can use it directly using path, without import as component:
<img src="/media/business/under-construction.svg" />
Hope it help!

Related

Why is the SvgIcon is not rendering in React MUI v5

I am trying to create a custom SVG component with material UI and typescript in rect that can be reused as an icon anywhere.
But, the icon is not rendering in the screen. I can't figure out why?
import { SvgIcon, SvgIconProps } from "#mui/material";
const ImgCompress: React.FunctionComponent<SvgIconProps> = (props) => {
return (
<SvgIcon
viewBox="0 0 512.000000 512.000000"
width="512.000000pt"
height="512.00000pt"
transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
stroke="none"
fill="#000000"
preserveAspectRatio="xMidYMid meet"
>
<path d="M15,19.16V15.07a4.27,4.27,0,0,0,6,0h0a4.27,4.27,0,0,0,0-6h0a4.27,4.27,0,0,0-6,0l-3,3-3,3a4.27,4.27,0,0,1-6,0h0a4.27,4.27,0,0,1,0-6h0A4.27,4.27,0,0,1,9,9" />
</SvgIcon>
);
};
export default ImgCompress;

SVG in React Component [duplicate]

This question already has answers here:
How to display svg icons(.svg files) in UI using React Component?
(16 answers)
Closed 12 months ago.
i've downloaded an svg image which i was intending in using it as a react component , but i paste the svg code to the functional component i get error markes within the tags , what i can do to fix this so ill be able to use the icon
import React from 'react'
const CardanoIcon = () => {
return (
<svg height="256" viewBox="0 0 256 256" width="256" xmlns="http://www.w3.org/2000/svg"><defs><style>
.cls-1 {
fill: #3468d1;
}
.cls-2 {
fill: #fff;
fill-rule: evenodd;
}
</style></defs><g data-name="cardano ada" id="cardano_ada"><g data-name="cardano ada" id="cardano_ada-2"><circle class="cls-1" cx="128" cy="128" data-name="Эллипс 6" id="Эллипс_6" r="128"/><path class="cls-2" d="M265.727,717.735a12.652,12.652,0,1,1-12.654,12.652A12.654,12.654,0,0,1,265.727,717.735Zm30.546,0a12.652,12.652,0,1,1-12.655,12.652A12.654,12.654,0,0,1,296.273,717.735Zm0,53.226a12.652,12.652,0,1,1-12.655,12.652A12.653,12.653,0,0,1,296.273,770.961Zm-30.546,0a12.652,12.652,0,1,1-12.654,12.652A12.653,12.653,0,0,1,265.727,770.961Zm-15.709-26.177a12.652,12.652,0,1,1-12.654,12.652A12.654,12.654,0,0,1,250.018,744.784Zm61.964,0a12.652,12.652,0,1,1-12.655,12.652A12.653,12.653,0,0,1,311.982,744.784Zm14.4-21.813a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,326.382,722.971Zm0,52.352a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,326.382,775.323Zm-90.764,0a7.853,7.853,0,1,1-7.854,7.853A7.854,7.854,0,0,1,235.618,775.323Zm0-52.352a7.853,7.853,0,1,1-7.854,7.853A7.854,7.854,0,0,1,235.618,722.971ZM281,696.794a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,281,696.794ZM281,801.5a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,281,801.5Zm33.6,7.853a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,314.6,809.353Zm-67.2,0a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,247.4,809.353Zm0-117.794a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,247.4,691.559Zm67.2,0a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,314.6,691.559Zm34.036,58.461a6.544,6.544,0,1,1-6.545,6.544A6.545,6.545,0,0,1,348.636,750.02Zm-135.273,0a6.544,6.544,0,1,1-6.545,6.544A6.544,6.544,0,0,1,213.363,750.02Zm-4.8-40.138a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,208.563,709.882Zm0,83.765a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,208.563,793.647Zm144.873,0a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,353.436,793.647Zm0-83.765a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,353.436,709.882ZM281,668a5.236,5.236,0,1,1-5.237,5.235A5.235,5.235,0,0,1,281,668Zm0,167.529a5.236,5.236,0,1,1-5.237,5.236A5.236,5.236,0,0,1,281,835.529Zm46.254-3.49a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,327.254,832.039Zm-92.509,0a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,234.745,832.039Zm0-158.8a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,234.745,673.235Zm92.509,0a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,327.254,673.235Zm45.382,79.4A4.363,4.363,0,1,1,368.273,757,4.363,4.363,0,0,1,372.636,752.637Zm-183.273,0A4.363,4.363,0,1,1,185,757,4.363,4.363,0,0,1,189.363,752.637Z" data-name="Эллипс 6 копия 29" id="Эллипс_6_копия_29" transform="translate(-152 -629)"/></g></g></svg>
)
}
export default CardanoIcon
create a file like an icon.svg and paste the SVG you have downloaded to that file then you can import SVG file in your component like this:
import icon from './icon.svg'
const CustomIcon = () => {
return (
<img src={icon} alt="icon" />
)
}
export default CustomIcon;
If you are using CRA (Create React App) for your React environment, I would suggest pulling out the contents of the <style> tag out into a separate .css file and then importing it into the React component.
So, your CardanoIcon.css would look as follows:
.cls-1 {
fill: #3468d1;
}
.cls-2 {
fill: #fff;
fill-rule: evenodd;
}
And your React component would look as follows - note the .css import on line 2. Also, note that you need to change class to className
import React from 'react';
import './CardanoIcon.css';
const CardanoIcon = () => (
<svg
height="256"
viewBox="0 0 256 256"
width="256"
xmlns="http://www.w3.org/2000/svg"
>
<defs></defs>
<g data-name="cardano ada" id="cardano_ada">
<g data-name="cardano ada" id="cardano_ada-2">
<circle
className="cls-1"
cx="128"
cy="128"
data-name="Эллипс 6"
id="Эллипс_6"
r="128"
/>
<path
className="cls-2"
d="M265.727,717.735a12.652,12.652,0,1,1-12.654,12.652A12.654,12.654,0,0,1,265.727,717.735Zm30.546,0a12.652,12.652,0,1,1-12.655,12.652A12.654,12.654,0,0,1,296.273,717.735Zm0,53.226a12.652,12.652,0,1,1-12.655,12.652A12.653,12.653,0,0,1,296.273,770.961Zm-30.546,0a12.652,12.652,0,1,1-12.654,12.652A12.653,12.653,0,0,1,265.727,770.961Zm-15.709-26.177a12.652,12.652,0,1,1-12.654,12.652A12.654,12.654,0,0,1,250.018,744.784Zm61.964,0a12.652,12.652,0,1,1-12.655,12.652A12.653,12.653,0,0,1,311.982,744.784Zm14.4-21.813a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,326.382,722.971Zm0,52.352a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,326.382,775.323Zm-90.764,0a7.853,7.853,0,1,1-7.854,7.853A7.854,7.854,0,0,1,235.618,775.323Zm0-52.352a7.853,7.853,0,1,1-7.854,7.853A7.854,7.854,0,0,1,235.618,722.971ZM281,696.794a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,281,696.794ZM281,801.5a7.853,7.853,0,1,1-7.855,7.853A7.853,7.853,0,0,1,281,801.5Zm33.6,7.853a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,314.6,809.353Zm-67.2,0a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,247.4,809.353Zm0-117.794a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,247.4,691.559Zm67.2,0a6.544,6.544,0,1,1-6.546,6.544A6.544,6.544,0,0,1,314.6,691.559Zm34.036,58.461a6.544,6.544,0,1,1-6.545,6.544A6.545,6.545,0,0,1,348.636,750.02Zm-135.273,0a6.544,6.544,0,1,1-6.545,6.544A6.544,6.544,0,0,1,213.363,750.02Zm-4.8-40.138a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,208.563,709.882Zm0,83.765a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,208.563,793.647Zm144.873,0a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,353.436,793.647Zm0-83.765a5.236,5.236,0,1,1-5.236,5.235A5.236,5.236,0,0,1,353.436,709.882ZM281,668a5.236,5.236,0,1,1-5.237,5.235A5.235,5.235,0,0,1,281,668Zm0,167.529a5.236,5.236,0,1,1-5.237,5.236A5.236,5.236,0,0,1,281,835.529Zm46.254-3.49a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,327.254,832.039Zm-92.509,0a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,234.745,832.039Zm0-158.8a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,234.745,673.235Zm92.509,0a4.363,4.363,0,1,1-4.363,4.363A4.363,4.363,0,0,1,327.254,673.235Zm45.382,79.4A4.363,4.363,0,1,1,368.273,757,4.363,4.363,0,0,1,372.636,752.637Zm-183.273,0A4.363,4.363,0,1,1,185,757,4.363,4.363,0,0,1,189.363,752.637Z"
data-name="Эллипс 6 копия 29"
id="Эллипс_6_копия_29"
transform="translate(-152 -629)"
/>
</g>
</g>
</svg>
);
export default CardanoIcon;

SVG sprite images not showing on iOS & Safari using React

I am trying to use my svg images with a sprite file. Importing sprite file in relevant component and using custom Svg component to render images with symbol id's. Svg image dimensions described in css classes. Everything works without any problems in Firefox and Chrome but mobile & desktop Safari does not rendering images. Based on suggestions, tried xmlns:xlink, width, height, viewBox attributes on svg tag. Nothing worked.
In source code I can see that SVG is present and it's taking space in page. But it's blank.
I appreciate any suggestions.
Here is my sprite file content:
<svg>
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5 8.586" id="icon-angle-left">
<g>
<g fill="none">
<path d="M0 0H6.981V3.491H0z" transform="translate(0.472 0.707) translate(3.821 3) rotate(90) translate(-2.809 0.331)"></path>
<path stroke="#555" stroke-linecap="round" d="M2577 1784.713l3.586 3.586 3.586-3.586" transform="translate(0.472 0.707) translate(3.821 3) rotate(90) translate(-2579.998 -1784.713)"></path>
</g>
</g>
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21 21" id="icon-home">
<path fill="none" d="M0 0h21v21H0z"></path>
<path fill="#555" d="M10.75 5.354l4.375 3.938v6.834h-1.75v-5.25h-5.25v5.25h-1.75V9.291l4.375-3.937m0-2.354L2 10.875h2.625v7h5.25v-5.25h1.75v5.25h5.25v-7H19.5z" transform="translate(-0.25 -0.375)"></path>
</symbol>
</svg>
Here is my Svg component:
import React from 'react';
import './style.scss';
const Svg = ({ symbolId, className }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" className={className}>
<use xlinkHref={symbolId}></use>
</svg>
);
};
export default Svg;
And using it like this;
import React from 'react';
import sprite from 'sprites/product-list.svg';
import Svg from 'shared/Svg';
const MyComponent = () => {
return (
<div>
<Svg className="image" symbolId={sprite + "#icon-home"} />
</div>
);
};
export default MyComponent;
It turns out that Safari does not support working with external svg files like this.
This is how we solved this situation:
Created a icons.jsx file that exports all the svg contents as a component. And used a prop for class name for further styling:
import React from 'react';
export const IconTick = ({ className }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16.662 12.505" id="icon-tick">
<path d="M14.151.431L5.629 8.953 2.511 5.835a1.471 1.471 0 0 0-2.08 2.08l4.159 4.158a1.469 1.469 0 0 0 2.08 0l9.562-9.562a1.471 1.471 0 0 0-2.081-2.08z" />
</svg>
);
export const IconTimes = ({ className }) => (
<svg className={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="icon-times">
<g id="Component_139_1" data-name="Component 139 – 1" transform="translate(1.414 1.414)">
<path id="Path_866" data-name="Path 866" d="m46.167 46.5-6 6 6 6" transform="translate(-34.167 -46.5)" />
<path id="Path_1015" data-name="Path 1015" d="m40.167 46.5 6 6-6 6" transform="translate(-40.167 -46.5)" />
</g>
</svg>
);
Created an alias in webpack.common.js for accessing svg's with a clean way:
module.exports = {
...
resolve: {
alias: {
...
icons: path.resolve(__dirname, 'src/SharedComponents/Icons/'),
...
},
...
},
...
};
And just used them like:
import React from 'react';
import { IconAngleLeft, IconTick } from 'icons';
const MyOtherComponent = () => {
return (
<div className="some-div">
<IconAngleLeft className={'foo'} />
<IconTick className={'bar'} />
</div>
);
};
export default MyOtherComponent;
It works everywhere without any problems and it's very easy I think. But you may need to correct your svg contents for Jsx syntax.

Create custom react material ui icon from double svg d path

I want to create a custom material ui icon from a svg file with two paths.
My code using
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { green } from '#material-ui/core/colors';
import SvgIcon from '#material-ui/core/SvgIcon';
const useStyles = makeStyles((theme) => ({
root: {
'& > svg': {
margin: theme.spacing(2),
},
},
}));
function GradIcon(props) {
return (
<SvgIcon {...props}>
<path
d="M142.45,174.613c-4.645,0-11.495-0.514-17.779-2.926l-50.271-19.366H49.774v30.162c0,9.274,6.9,19.802,15.405,23.499
l60.872,26.496c8.505,3.691,22.312,3.707,30.826,0.036l61.536-26.574c8.508-3.671,15.41-14.183,15.41-23.457v-30.162h-27.175
l-44.547,18.78C156.742,173.365,149.756,174.613,142.45,174.613z"
/>
<path
d="M6.475,112.944l121.222,46.709c8.661,3.329,22.603,3.112,31.152-0.492l115.768-48.801v71.999l-7.151,23.866h20.682
l-7.399-24.114V107.45h-0.208c4.997-3.449,3.832-7.747-3.567-10.393L159.196,55.146c-8.74-3.117-22.859-2.985-31.545,0.277
L6.529,100.99C-2.157,104.258-2.178,109.612,6.475,112.944z"
/>
</SvgIcon>
);
}
export default function SvgIconsColor() {
const classes = useStyles();
return (
<div className={classes.root}>
<GradIcon />
</div>
);
}
like in the docs didn't work out. As I am fairly new to javascript and react I thought I'd ask on here.
Thanks
I solved it by creating a separate component with the following Layout like in this tutorial:
First I converted the image online to an svg.
Then I opened it within an editor and selected the whole svg part.
This part is posted within the component like below. Be sure to disable any unnecessary properties, and set the width and height to 24. The properties below should be enough. Don't delete parts. Just comment out and try till it fits your desired output.
import React from "react";
const IconName = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
version="1.1"
viewBox="<viewBox>"
<path d="<path>"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
fill="<color>"
fill-rule="evenodd"
/>
</svg>
);
};
export default IconName;
Then just import the icon to the component you need it in.
The number of paths doesn't matter, just remember to include all the properties after the path.

The tag <ReactComponent> is unrecognized in this browser

I'm going some test with jest, I'm currently testing component which using svg. I'm using ReactComponent to display my svg as react suggest us to do.
When I'm launching my test I always have this message :
Warning: The tag is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter. at ReactComponent
So my code Look like this :
import React, { ReactElement, useState } from "react";
// SVG;
import { ReactComponent as Play } from "../../../../../../../../assets/svg/PLAY.svg";
export interface IComponentProps {
valueX: valueX;
color: string;
}
export default function Component({
valueX,
color,
}: IComponentProps): ReactElement {
const [state, setState] = useState<boolean>(false);
return (
<div className="wrapper-lesson-video">
<div className="display-colum">
<div
className="pickgradient"
style={{
background: `linear-gradient( to bottom, rgba(0, 0, 0, 0.5) 0%, ${color} 100% )`,
}}
>
<img
alt="title"
src="https://cdn.xxxx.com/photo/xxxx.jpg"
/>
</div>
<div className="launcher-wrapper">
<div className="launcher-menu">
<h1 className="secondMinor uppercase">
{valueX.last}.{valueX.current} {valueX.title}
</h1>
<p className="secondMinor m-t-20">{valueX.time}</p>
<div
className="major-button center-elements m-t-20"
onClick={() => setState(!state)}
>
<div>Button</div>
<div
className="cursor-pointer svg-lesson"
style={{ fill: "white" }}
>
<Play width="30px" height="30px" />
</div>
</div>
</div>
</div>
</div>
</div>
);
}
the following code is part of my test
function initWrapper(initStore, props) {
wrapper = mount(
<Provider store={initStore}>
<MemoryRouter>
<Router>
<Component {...minProps} />
</Router>
</MemoryRouter>
</Provider>
);
return;
}
it("Run index is ran", async () => {
initWrapper(storeFullyFill, minProps);
expect(wrapper.find("Memo(component)").length).toBe(1);
expect(wrapper).toBeTruthy();
});
One of my svg:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="current" height="current" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ICONS/PLAY</title>
<defs>
<polygon id="path-1-play" points="0 0 9.75 6.19051525 0 12"></polygon>
</defs>
<g id="ICONS/PLAY" stroke="none" stroke-width="1" fill="current" fill-rule="evenodd">
<g id="Rectangle-play" transform="translate(10.000000, 9.000000)">
<mask id="mask-2-play" fill="current">
<use xlink:href="#path-1-play"></use>
</mask>
<use id="play-mask-1" fill="current" fill-rule="nonzero" xlink:href="#play-1"></use>
<rect fill="current" mask="url(#mask-2-play)" x="-10" y="-9" width="30" height="30"></rect>
</g>
</g>
</svg>
Do you thing this is temporary warning that'll be fix ? or can I do something to fix / mute it ?
You need to mock SVG files as jest struggles with SVG for some reason.
Create a __mock__ folder. The directory should be adjacent to node_modules. The setup should be:
svgrMock.js:
//__mocks__/svgrMock.js
import * as React from 'react'
export default 'SvgrURL'
export const ReactComponent = 'svg'
package.json
...
"jest": {
"moduleNameMapper": {
"\\.svg": "<rootDir>/__mocks__/svgrMock.js"
}
},
Just bear in mind only the following are valid methods for importing SVGs after this fix:
import logoURL from '../assets/logo.svg'
// and
import { ReactComponent as Logo } from '../assets/logo.svg'
Full details: https://react-svgr.com/docs/jest/
According to this:
For those finding this issue coming from other projects:
This can be fixed by adding xmlns="http://www.w3.org/2000/svg" to any offending SVG element, including <g>, <use>, <text>, or <tspan> (doesn't break spec, but does pollute attribute list).
You could also run tests in something other than __DEV__ mode, or add the is attribute (breaks HTML spec, requires test selectors to be rewritten).
https://github.com/facebook/react/blob/993ca533b42756811731f6b7791ae06a35ee6b4d/packages/react-dom/src/client/ReactDOMComponent.js#L442

Resources