Reputation: 17608
I'm importing the SVG with ReactComponent
. Here is the related code:
import { ReactComponent as SuccessSVG } from "success.svg";
function SuccessIcon() {
return <SuccessSVG />;
}
and this is the SVG itself:
<svg viewBox="0 0 233.3 233.3">
<circle class="circle" cx="116.65" cy="116.65" r="116.65" />
<path
class="ok"
d="M97.28,167.38l-33.7-33.7a6.34,6.34,0,1,1,9-9l29.21,29.21,76-76a6.34,6.34,0,1,1,9,9l-80.48,80.48A6.34,6.34,0,0,1,97.28,167.38Z"
transform="translate(-8.51 -6.01)"
/>
</svg>
I want to change circle
's and path
's colors dynamically via props. Something like this obviously:
function SuccessIcon({ circleColor, pathColor) {
...
...
}
I've seen this question already. I don't want to use the accepted answer's solution. The other answer is closer to my desire but I couldn't make it work.
By the way, I don't want to use the SVG directly in my component.
Upvotes: 1
Views: 1786
Reputation: 1248
I still have not found a good solution for this problem. But I found this:
https://www.w3.org/TR/SVGParamPrimer/ : With this, we can write a webpack-loader, wrap the svg as data-url in an object
element on it's data
property, so we can pass props. And we can detect the props type from where it's used in the svg file. Of course, we need to write our svg in that syntax: <rect fill="param(color) blue" stroke="param(outline) navy" />
https://tabatkins.github.io/specs/svg-params/: This is't official, don't know will it be implemented.
Since solution one need to write the svg in that syntax, maybe it has no difference from copy svg code to jsx file and do some small changes.
I have another idea:
import SvgCar from './car.svg';
const vdom = <SvgCar>
<replace
// path="a relative path point to an element or a property"
path="children[2].fill"
to={'red'} />
</SvgCar>;
// or
const vdom2 = <SvgCar>{vdom => {vdom.children[2].fill="red";}}</SvgCar>
But I think this way will import so much coupling. It's not a good idea.
Upvotes: 0
Reputation: 21307
You've already extracted SuccessSVG
to its own component. Now you just need to pass via props
the configurations you want to be dynamic
const SuccessSvg = ({ cx, cy }) => {
return (
<svg viewBox="0 0 233.3 233.3" >
<circle class="circle" cx={cx} cy={cy} r="116.65" />
<path
class="ok"
d="M97.28,167.38l-33.7-33.7a6.34,6.34,0,1,1,9-9l29.21,29.21,76-76a6.34,6.34,0,1,1,9,9l-80.48,80.48A6.34,6.34,0,0,1,97.28,167.38Z"
transform="translate(-8.51 -6.01)"
/>
</svg>
)
}
const Component = () =>{
return(
<SuccessSvg color='blue' />
)
}
Sadly you must consider the tradeoff. By declaring your svg
as a stand alone component you write more code and have control over the customization. So that you can pass props which will be deeply applied inside your jsx
structure
const CustomSVG = ({ svgProps, circleProps }) =>{
return(
<svg {...svgProps}>
<circle {...circleProps} />
</svg>
)
}
This is why the OP for the linked question wraps the svg into a component, so that he can inject a custom className
into the svg. Declarative components are awesome but you are limited by their API. In your case I don't see much alternatives, either abstract the structure to it's own component or use nested selectors.
Upvotes: 3
Reputation: 53874
If you don't want to use a component as @Dupocas suggested, your only way is to style your SVG
:
// Example of CSS-in-JS , can be achieved with simple className.
const SVGContainer = styled.div`
svg {
path {
fill: ${({ circleColor }) => circleColor};
}
}
`;
function SuccessIcon({ circleColor }) {
return (
<SVGContainer circleColor={circleColor}>
<SuccessSVG />
</SVGContainer>
);
}
const App = () => {
return <SuccessIcon circleColor="palevioletred" />;
};
Upvotes: 2