0

I'm making a request in my react project to fetch svgs using axios and I get back the svg data as a string. How can I change all path fill values in the string to a specified color?

This is roughly my React component:

export const ColorSvg = props => {

  const [
    state,
    setState
  ] = React.useState({
    svgData: undefined,
  });

  React.useEffect(() => {

    if (!props.src) {
      return;
    }

    myAxiosGet(props.src) // my custom wrapper for axios
      .then(res => {

        if (res.ok) {

          // before converting to base64 I would like to change all path fill values to props.color
          const color = props.color;

          const base64data = btoa(unescape(encodeURIComponent(res.data)));

          setState(prevState => ({
            ...prevState,
            svgData: base64data
          }));
        }
      })
  }, [props.color, props.src]);

  return (
    <>
    { state.svgData &&

      <img height={props.height} width={props.width} src={`data:image/svg+xml;base64,${state.svgData}`} alt="" />
    }
    </>
  );
};

The svg string data I get back(i.e. res.data) is as follows:

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.862154 9.414C0.0811059 8.63295 0.0811042 7.36662 0.862153 6.58557L1.95111 5.49661V3.95318C1.95111 2.84861 2.84654 1.95318 3.95111 1.95318H5.49454L6.58557 0.862154C7.36661 0.0811059 8.63295 0.0811042 9.41399 0.862153L10.505 1.95318H12.0452C13.1498 1.95318 14.0452 2.84861 14.0452 3.95318V5.4934L15.1374 6.58557C15.9185 7.36661 15.9185 8.63295 15.1374 9.41399L14.0452 10.5062V12.0473C14.0452 13.1519 13.1498 14.0473 12.0452 14.0473H10.5041L9.414 15.1374C8.63295 15.9185 7.36662 15.9185 6.58557 15.1374L5.49547 14.0473H3.95112C2.84655 14.0473 1.95111 13.1519 1.95111 12.0473V10.503L0.862154 9.414ZM7.73026 10.7313L12.016 6.73134L10.6513 5.26923L7.04794 8.6324L5.34931 7.04701L3.98467 8.50912L6.36563 10.7313L7.04794 11.3682L7.73026 10.7313Z" fill="#0EBC73"/>
</svg>

How can I iterate over ALL path elements and change their fill value to props.color? I'd imagine I would have to parse the string into xml format and then iterate over all elements and if element is path and fill exists then change it to props.color, which may be unnecessary to have to write from scratch as opposed to using an existing npm package.

MShakeG
  • 391
  • 7
  • 45
  • why not using CSS? along with a normal svg element – Joseph Khella Jun 16 '22 at 13:44
  • @JosephKhella I would like to use my custom axios provider which enables caching strategies – MShakeG Jun 16 '22 at 13:48
  • 1
    please take a look at this https://stackoverflow.com/questions/72615923/regex-to-remove-attribute-from-specific-svg-element-in-string#comment128272146_72615923 – enxaneta Jun 16 '22 at 14:05
  • In case you control the code of the SVG strings and just want to change the fill color dynamically at runtime, you could just as well set the fill attribute to "currentcolor" in your SVG code and then wrap the img tag in
    – Steffen Frank Jun 16 '22 at 14:16

1 Answers1

1

This answer pointed out by enxaneta works. All I have to do is before base64 encoding execute the following line that replacing all path fill with a specified color:

const svgString = res.data;
const colorisedSvgString = svgString.replace(/(?<=<path\b[^<>]*)\s*\bfill=(["']).*?\1/, ` fill="${props.color}"`);
// now encode colorisedSvgString

To replace all occurences use:

const colorisedSvgString = svgString.replaceAll(/(?<=<path\b[^<>]*)\s*\bfill=(["']).*?\1/g, ` fill="${color}"`);

The above regex also includes "none", which you might want to leave unchanged, in that case the following should work to ignore "none":

const colorisedSvgString = svgString.replaceAll(/(?<=<path\b[^<>]*)\s*\bfill=(["'](?!none)).*?\1/g, ` fill="${color}"`);
MShakeG
  • 391
  • 7
  • 45