IAspireToBeGladOS
IAspireToBeGladOS

Reputation: 1484

React - Ability to control fill color of an SVG through props

I have a SVG, here called "example.svg", that's being called and created as a component, like so:

import { ReactComponent as Example } from './example.svg';
import styles from './index.module.css';

const ExampleImg = ({ ...otherProps }) => (
  <Example className={styles.image} {...otherProps} />
);

export default ExampleImg;

This component is being called elsewhere - say on myPage - like this:

const myButton = <ExampleImg {...nextButtonProps} />;

My problem is this:

I need to be able to control the fill color of the SVG by inserting a prop that can be controlled from outside the SVG. The SVG in question:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 216 216" style="enable-background:new 0 0 216 216;" xml:space="preserve">
<style type="text/css">
    .st0{fill:#FFFFFF;}
    .st1{fill:#0969A6;}
    .st2{fill:#36BC0A;}
    .st3{fill:#C41C1C;}
    .st4{fill:#CECECE;}
    .st5{fill:#FEFEFE;}
    .st6{fill:#FFFFFF;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;}
    .st7{fill:#FFFFFF;stroke:#FFFFFF;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<circle class="st4" cx="107.25" cy="109.75" r="68.75"/>
<path class="st5" d="M149.79,104.21c2.58,4.89,1.33,9.67-3.32,12.55c-1.33,0.83-2.86,0.97-4.37,0.97c-15.97,0.01-31.94,0-47.91,0
    c-0.76,0-1.51,0-2.42,0c0.46,1.13,1.38,1.71,2.08,2.41c5.01,5.04,10.04,10.07,15.13,15.03c3.96,3.85,3.48,8.88,1.63,11.57
    c-3.39,4.92-9.95,5.24-14.26,0.87c-7.76-7.86-15.61-15.63-23.42-23.44c-2.92-2.92-5.78-5.92-8.77-8.77
    c-2.94-2.8-3.79-8.71-0.42-12.31c0.62-0.66,1.21-1.34,1.82-2.02c0.19,0.02,0.32-0.05,0.35-0.25c0.06-0.05,0.11-0.11,0.14-0.18
    c0.51-0.28,0.93-0.65,1.13-1.22c0,0,0.05-0.04,0.05-0.04c0.53-0.14,0.89-0.47,1.06-1c0,0,0.02-0.02,0.02-0.02
    c2.81-2.51,5.36-5.27,8.02-7.93c6.86-6.87,13.71-13.74,20.56-20.61c4.31-4.33,10.5-3.39,13.84,1.71c2.23,3.41,1.51,7.98-1.81,11.27
    c-3.55,3.52-7.13,7-10.64,10.56c-0.86,0.88-2.02,1.53-2.47,2.79c0,0-0.03,0.02-0.03,0.02c-1.05,0.54-1.81,1.37-2.42,2.36
    c0,0-0.05,0.05-0.05,0.05c-0.22,0.12-0.48,0.19-0.64,0.36c-0.28,0.32-0.85,0.58-0.6,1.09c0.19,0.4,0.73,0.19,1.11,0.25
    c0.15,0.02,0.3-0.01,0.45-0.01c14.09,0,28.18-0.02,42.27,0.02c3.56,0.01,7.16-0.4,10.63,0.84c0.07,0.05,0.14,0.08,0.22,0.1
    c0.2,0.33,0.49,0.55,0.88,0.6c0.03,0.07,0.08,0.13,0.14,0.17c0.03,0.28,0.21,0.4,0.47,0.42c0,0,0.03,0.03,0.03,0.03
    c0.07,0.31,0.28,0.49,0.59,0.56c0,0,0.02,0.02,0.02,0.02c0.02,0.26,0.15,0.43,0.41,0.48c0.02,0.07,0.06,0.13,0.12,0.18
    C149.45,103.91,149.56,104.1,149.79,104.21z"/>
</svg>

Specifically, .st4 is the class that needs a prop inserted, something like {fill: {currentColor}}.

Then, you can pass in currentColor through the myPage props when it calls ExampleImg to control the fill depending on the condition.

I honestly don't have any idea how to approach this, so any guidance would be much appreciated!

Upvotes: 3

Views: 15316

Answers (3)

Robert Hogan
Robert Hogan

Reputation: 81

I used a combination of the two answers to style my react component. The API information was limited and I checked to see if the prop passed was true and added the bg-mountain class for additional styling. The index.css is my global stylesheet and the mountain.css is my component stylesheet (which will eventually be a mountain.module.css).

// index.css

svg {
  width: auto;
  height: auto;
  fill: currentColor;
}

// App.js

import Mountain from './terrainSurface/Mountain';
import './PlanetTerrain.css';

const PlanetTerrain = ({ terrain }) => {
  const grassSurfaces = terrain.filter((terrainSurface) => {
    const pickedTerrain = terrainSurface.includes('grass');
    return pickedTerrain;
  });

  return (
    <div
      className={`planet-background relative h-96 w-full top-0 text-black z-1 overflow-y-hidden`}
    >
      {grassSurfaces.map((grassSurface) => {
        return (
          <Mountain
            key={grassSurface}
            className={`mountain absolute h-full -bottom-4 z-2`}
            surfaceColor={grassSurface}
          />
        );
      })}
    </div>
  );
};
export default PlanetTerrain;

// Mountain.js

const Mountain = ({ surfaceColor }) => {
  return (
    <>
      <p>{surfaceColor}</p>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 1440 320"
        className={`h-full bottom-1 absolute -z-1 ${
          surfaceColor ? 'bg-mountain' : ''
        }`}
      >
        <path
          fill="#000"
          fillOpacity="1"
          className="mountain-border"
          d="M0,192L130.9,96L261.8,160L392.7,96L523.6,64L654.5,160L785.5,32L916.4,224L1047.3,256L1178.2,192L1309.1,0L1440,64L1440,320L1309.1,320L1178.2,320L1047.3,320L916.4,320L785.5,320L654.5,320L523.6,320L392.7,320L261.8,320L130.9,320L0,320Z"
        ></path>
        <path
          className="mountain-svg"
          fillOpacity="1"
          d="M0,192L130.9,96L261.8,160L392.7,96L523.6,64L654.5,160L785.5,32L916.4,224L1047.3,256L1178.2,192L1309.1,0L1440,64L1440,320L1309.1,320L1178.2,320L1047.3,320L916.4,320L785.5,320L654.5,320L523.6,320L392.7,320L261.8,320L130.9,320L0,320Z"
        ></path>
      </svg>
    </>
  );
};
export default Mountain;

// Mountain.css

.bg-mountain {
  fill: #622c22;
}

Still working through the project and I'll update if I find a better solution.

Upvotes: 1

GProst
GProst

Reputation: 10227

So did I understand correctly that this SVG will be rewritten as a React component? (which I'd probably do unless some important reasons). CSS actually has currentColor key value for a color property, so you can controll the color from outside, i.e.:

.svg-container {
  color: black; // or whatever color really
}

.st4 {
  fill: currentColor;
}

Upvotes: 4

severestrength
severestrength

Reputation: 312

I would recommend actually putting the SVG into your code and passing it in as a prop:

import { ReactComponent as Example } from './example.svg';
import styles from './index.module.css';

const ExampleImg = ({ ...otherProps }) => (
  <Example className={styles.image} {...otherProps}>
    <svg {...}>
      <style>{`
      .st1{${props.fill}} 
      `}
      </style>
    </svg>
  </Example>
);

export default ExampleImg;

Upvotes: 0

Related Questions