Reputation: 43
I have a folder name icons
that contains a lot of SVG files. Every file is an independent icon that looks like that:
icons/heart.svg (I want to avoid converting it to JS)
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M22.178 13.583l-9.131 8.992a1.502 1.502 0 0 1-2.094 0l-9.131-8.992a6.192 6.192 0 0 1 0-8.773c2.439-2.413 6.395-2.413 8.834 0L12 6.154l1.344-1.344c2.439-2.413 6.395-2.413 8.834 0a6.192 6.192 0 0 1 0 8.773"/></svg>
I want to create a component that will load an svg based on its name.
components/Icon.js
export const Icon = ({ name, ...props }) => {
return (
<svg height="24" width="24" viewBox="0 0 24 24" role="img">
<path d={name} />
</svg>
);
};
Example usage I look for: (App.js)
<Icon name="heart" /> // should load heart.svg
<Icon name="star" /> // should load star.svg
Upvotes: 2
Views: 6171
Reputation: 21143
You don't have to convert SVG icon files to JS; it has already been done.
<svg-icon is=heart></svg-icon>
<svg-icon is=heart fill="green" scale=".8"></svg-icon>
<svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
<svg-icon is=smile></svg-icon>
<svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
But.. it is a modern W3C standard Web Component <svg-icon is="heart"></svg-icon>
Alas React doesn't comply with modern Web Standards so you have to make it work in React.
For the IconMeister Web Component: https://iconmeister.github.io/
I converted 7300+ icons from major iconsets to JSON notation:
With this JSON (note you can specifiy different viewBoxes from different Icon Sets)
{
"heart" : "box:36;fill:red;path:M33 8c-1-3-5-5-10-4A10 10 0 0018 8A10 10 0 0013 4C8 3
4 5 3 8c-2 4-1 8 2 13c3 4 7 7 12 12a1 1 0 001 0c5-5 9-8 12-12c4-5 4-9 3-13z",
"smile": "box:128;fill:#000;path:M62 2C28 2 0 30 0 64s28 62 62 62s62-28 62-62S97 2 62 2z
m0 112c-28 0-50-23-50-50S35 14 62 14s50 23 50 50s-23 50-50 50zm30-37c-3-3-7-2-9
1c-6 7-13 10-21 10s-16-4-21-10c-3-3-6-3-9-1c-3 3-3 6-1 9c8 9 19 15 31 15s23-6
31-15c3-3 2-7-1-9zM42 60c5 0 8-4 8-8s-4-8-8-8s-8 4-8 8s4 8 8 8zm40-15c-7 0-14
5-15 11c-1 3 3 5 5 3l3-3c4-4 12-4 16 0l3 3c3 2 6 0 5-3c-1-7-9-11-15-11z"
}
The 796 Bytes! <svg-icon>
Web Component uses standard HTML to create and control SVG:
<svg-icon is=heart></svg-icon>
<svg-icon is=heart fill="green" scale=".8"></svg-icon>
<svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
<svg-icon is=smile></svg-icon>
<svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
and style:
<style>
svg-icon {
display:inline-block;
width:120px;
background:lightgreen;
}
</style>
Outputs:
No Libraries, No Frameworks, No external SVG files, No dependencies
Documentation and source at: https://iconmeister.github.io/
<style>
svg-icon {
display:inline-block;
width:120px;
background:lightgreen;
}
</style>
<svg-icon is=heart></svg-icon>
<svg-icon is=heart fill="green" scale=".8"></svg-icon>
<svg-icon is=heart fill="green" scale=".8" rotate="45"></svg-icon>
<svg-icon is=smile></svg-icon>
<svg-icon is=smile fill="gold" stroke="green" width="5"></svg-icon>
<script>
((t,e={path:(t,e="")=>`<path d='${t}' ${e}/>`},i={stroke:"#000",rect:"<rect width='100%' height='100%' fill='{tile}' {border}/>",fill:"none",tile:"none",img:1,width:1,scale:1,opacity:1,is:"",border:"",filter:"",top:"",v1:"",v2:"",v3:"",box:9,rotate:0,xy:0,w:0,h:0,api:[t,e]})=>{customElements.define("svg-icon",class extends HTMLElement{static get observedAttributes(){return Object.keys(i)}attributeChangedCallback(){this.svg()}svg(s=this,r=s.A||Object.keys(s.A={...i}).map((t=>Object.defineProperty(s,t,{set:e=>s.setAttribute(t,e),get:()=>s.getAttribute(t)||getComputedStyle(s).getPropertyValue("--svg-icon-"+t).replace(/"/g,"").trim()||s.A[t]},e[t]=e=>(s.A[t]=e,"")))),l,a=(t[s.is]||"").split`;`.map((t=>([r,l]=t.trim().split`:`,e[r]?e[r].apply(s,l.split`,`):t))).join``,o=s.box/2,c=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${s.w||s.box} ${s.h||s.box}' style='vertical-align:top'>${s.rect}<g stroke-width='{width}' stroke='{stroke}' fill='{fill}' opacity='{opacity}' filter='{filter}' transform='translate({xy}) matrix({scale} 0 0 {scale} ${o-o*s.scale} ${o-o*s.scale}) rotate({rotate} ${o} ${o})'>${a}</g>${s.top}</svg>`.replace(/{\s?([^{}\s]*)\s?}/g,((t,e)=>s[e]))){return s.innerHTML=1==s.img?`<img style='vertical-align:top' src="data:image/svg+xml,${c.replace(/#/g,"%23")}">`:c}})})(
{"heart":"box:36;fill:red;path:M33 8c-1-3-5-5-10-4A10 10 0 0018 8A10 10 0 0013 4C8 3 4 5 3 8c-2 4-1 8 2 13c3 4 7 7 12 12a1 1 0 001 0c5-5 9-8 12-12c4-5 4-9 3-13z",
"smile":"box:128;fill:#000;path:M62 2C28 2 0 30 0 64s28 62 62 62s62-28 62-62S97 2 62 2zm0 112c-28 0-50-23-50-50S35 14 62 14s50 23 50 50s-23 50-50 50zm30-37c-3-3-7-2-9 1c-6 7-13 10-21 10s-16-4-21-10c-3-3-6-3-9-1c-3 3-3 6-1 9c8 9 19 15 31 15s23-6 31-15c3-3 2-7-1-9zM42 60c5 0 8-4 8-8s-4-8-8-8s-8 4-8 8s4 8 8 8zm40-15c-7 0-14 5-15 11c-1 3 3 5 5 3l3-3c4-4 12-4 16 0l3 3c3 2 6 0 5-3c-1-7-9-11-15-11z"});
</script>
PS. The source is UNlicensed, I would love to see a React version in 796 Bytes (GZipped)
Upvotes: 2
Reputation: 1883
You can create a file which exports all your svg file and give name to each one of them.
import heart from './icons/heart.svg'
export { heart };
Then you can import your icon anywhere you want according to the name;
import { heart } from './<path_of_above_file>'
if you want to create an Icon component then create a component and render the icon in there.
export const Icon = ({ icon, ...props }) => {
return (
<div {...props}>
{icon}
</div>
);
};
Then use it anywhere you like.
import { heart } from './path_of_above_file';
<Icon icon={heart} />
Another solution is passing path as a prop;
export const Icon = ({ path, ...props }) => {
return (
<svg {...props} viewBox="0 0 24 24" role="img">
<path d={path} />
</svg>
);
};
And use the icon passing the path as a prop.
<Icon path='M22.178 13.583l-9.131 8.992a1.502 1.502 0 0 1-2.094 0l-9.131-8.992a6.192 6.192 0 0 1 0-8.773c2.439-2.413 6.395-2.413 8.834 0L12 6.154l1.344-1.344c2.439-2.413 6.395-2.413 8.834 0a6.192 6.192 0 0 1 0 8.773' height="24" width="24" />
Upvotes: 6
Reputation: 53874
You can have an object to map path
name to its value:
const PATHS = {
star: "M22.178 ...",
heart: "A22.153 ...",
};
export const Icon = ({ name, ...props }) => {
return (
<svg height="24" width="24" viewBox="0 0 24 24" role="img">
<path d={PATHS[name]} />
</svg>
);
};
Upvotes: 0