Dynamically load svgs as components in react - reactjs

My issue is basically this:
I have a bunch of svg images all stored in a .js file like this
import React from 'react'
export const React = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="#c90016"/></svg>
export const Angular = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="#c90016"/></svg>
export const JQuery = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="#c90016"/></svg>
in another component I want to render correct image based on an array, so for instance I have:
import {React,Angular,JQuery} from '../svgs'
const images = [
'React','React','JQuery','Angular','JQuery'
]
no I want to render each image, actually to do something like this
<div>
images.map (image => <image>)
</div>

you have to make some changes in svgs.js as you are exporting a named constant React again so it will throw duplication error when you import it.
import React from 'react'
export const react = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="#c90016"/></svg>
export const angular = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="#c90016"/></svg>
export const jQuery = () =>
<svg width="40" height="40" viewBox="0 0 256 256"><ellipse cx="238.456" cy="39.252" rx="28.346" ry="26.522" fill="green"/></svg>
After that import them where you want
import {react, angular, jQuery} from '../svgs'
// don't use quotes as it represents string
// const images = [
// 'react', 'angular', 'jQuery'
// ]
const images = [
react, angular, jQuery
]
And last use them in jsx
render() {
return (
<div>
// use uppercase letter for React component
{images.map((Image, index) => <Image key={index} />)}
</div>
)
}

Related

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

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!

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.

Render React SVG component as backgroundImage

I am trying to render a React Component that returns an <svg> as a backgroundImage of a <div>.
Currently I am using ReactDOMServer with renderToStaticMarkup or renderToString but nothing shows up:
const SvgComponent = () => {
return (
<svg xmlns='http://www.w3.org/2000/svg'><rect fill='red' x='0' y='0' /></svg>
)
}
const ParentComponent = () => {
return (
<div
className={classes.banner}
style={{
backgroundImage: `url("data:image/svg+xml;utf8, ${ReactDOMServer.renderToStaticMarkup(<SvgComponent />)} ")`
}}
>
</div>
)
}
Would the package jsx-to-string the way to do it?
You have to use encodeURIComponent() to URI encode the SVG data because React will not render the SVG data if it is not URI encoded. So,
const svgString = encodeURIComponent(renderToStaticMarkup(<SvgComponent />));
Also, set the width and height in <rect> of SVG like,
<rect fill="red" width={100} height={100} />
So final code should look like,
import ReactDOM from "react-dom";
import { renderToStaticMarkup } from "react-dom/server";
import React from "react";
const SvgComponent = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg">
<rect fill="red" width={100} height={100} />
</svg>
);
};
const ParentComponent = () => {
const svgString = encodeURIComponent(renderToStaticMarkup(<SvgComponent />));
return (
<div
style={{
backgroundImage: `url('data:image/svg+xml;utf8, ${svgString}')`,
width:500,
height:500
}}
>
</div>
)
}
ReactDOM.render(<ParentComponent />, document.getElementById("root"));
I have setup the same in CodeSandbox,
ReactDOMServer.renderToStaticMarkup uses double quotes in the markup, so it returns
<svg xmlns="http://www.w3.org/2000/svg"><rect fill="red" width="10" height="10"></rect></svg>
And because you also used double quotes in url("...") it gives invalid markup.
So just use single quotes in url('...') and it should work.
Note: This will probably break if react changes how renderToStaticMarkup is implemented!

Resources