I wanted to import too many SVG icons in app & each icons required custom color through css, which is the easiest way to import to react?
Importing to <img/>
tag won't support the color change via css fill.
Creating a .js component for each icon is too hard for 250 icons.
what is the other option ? Please help
import IconArrow from "./Arrow.svg";
import Circlearrowdownright from "./Arrow.js";
<img className="ico" src={IconArrow} />
<i className="ico"><Circlearrowdownright /></i>
https://codesandbox.io/s/svg-icon-3z0qu6
CodePudding user response:
You can import and use it as React component directly:
import { ReactComponent as ExampleIcon} from './icons/ExampleIcon.svg';
<ExampleIcon className="css-class"/>
CodePudding user response:
You can dynamically import SVG & render on the fly (CodeSandbox). No need to create a separate .js
component for every SVG file.
The hook
function useDynamicSVGImport(name, options = {}) {
const ImportedIconRef = useRef();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const { onCompleted, one rror } = options;
useEffect(() => {
setLoading(true);
const importIcon = async () => {
try {
ImportedIconRef.current = (
await import(`./${name}.svg`)
).ReactComponent;
if (onCompleted) {
onCompleted(name, ImportedIconRef.current);
}
} catch (err) {
if (onError) {
one rror(err);
}
setError(err);
} finally {
setLoading(false);
}
};
importIcon();
}, [name, onCompleted, one rror]);
return { error, loading, SvgIcon: ImportedIconRef.current };
}
Icon
component that uses the hook
/**
* Simple wrapper for dynamic SVG import hook. You can implement your own wrapper,
* or even use the hook directly in your components.
*/
export const Icon = ({ name, onCompleted, one rror, ...rest }) => {
const { error, loading, SvgIcon } = useDynamicSVGImport(name, {
onCompleted,
one rror
});
if (error) {
return error.message;
}
if (loading) {
return "Loading...";
}
if (SvgIcon) {
return <SvgIcon {...rest} />;
}
return null;
};
Usage
return (
<>
<Icon
name="Arrow"
fill="gray"
width="100"
onCompleted={handleOnCompleted}
one rror={handleIconError}
/>
<Icon
name="delete"
fill="gray"
width="50"
onCompleted={handleOnCompleted}
one rror={handleIconError}
/>
</>
);
CodePudding user response:
React works fine with native Web Components. Only when you want to interact with them using Events or pass Data is where React (still) fails to support the standard: https://custom-elements-everywhere.com/
- Creating a
<svg-icon>
tag is only a few lines of code. - Added a
replaceWith
attribute so the<svg>
you load replaces the<svg-icon>
, makes it easier to work with global CSS. - Added a
shadowRoot
attribute to move any content TO shadowDOM
customElements.define("svg-icon", class extends HTMLElement {
async connectedCallback(
src = this.getAttribute("src"),
shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
) {
shadowRoot.innerHTML = await (await fetch(src)).text()
shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))
this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
}
});
body {
display: grid;
grid: 1fr/1fr 5fr;
}
path {
stroke: green;
stroke-width: .2;
fill: red;
}
<svg-icon replaceWith src="https://svg-cdn.github.io/bi-arrows.svg"></svg-icon>
<svg-icon src="https://svg-cdn.github.io/simple-worldmap.svg">
<style shadowRoot>
path {
fill: orange
}
</style>
</svg-icon>