Home > Blockchain >  How to Import SVG icons in React
How to Import SVG icons in React

Time:05-11

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>

  • Related