I am using React to help manage my SVG icons:
const Trash = ({
fill, width, height,
}) => (
<svg width={ `${width}px` } height={ `${height}px` } xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 17.92 20.42">
<path style={ { fill } } d="M14,20.3H3.91a0.5,0.5,0,0,1-.5-0.47l-0.89-14A0.5,0.5,0,0,1,3,5.35H14.9a0.5,0.5,0,0,1,.5.53l-0.89,14A0.5,0.5,0,0,1,14,20.3Zm-9.63-1h9.16l0.83-13H3.56Z" />
<rect style={ { fill } } x="5.69" y="5.84" width="1" height="13.98" transform="translate(-0.68 0.35) rotate(-3.1)" />
...
</svg>
);
I manage changing colours based on state in a wrapper:
const makeIcon = Icon => props => <IconWrapper { ...props }><Icon /></IconWrapper>;
export const TrashIcon = makeIcon(Trash);
The wrapper looks like this (heavily abridged):
class IconWrapper extends Component {
constructor(props) {
super(props);
this.state = {
isActive: false,
isHovered: false,
};
}
handleClick(e) {
if (this.props.onClick) {
this.props.onClick(e);
}
this.setState({
isActive: !this.state.isActive,
});
}
...
render() {
const Icon = React.cloneElement(
this.props.children,
{
isActive: this.state.isActive,
fill: this.getFill(),
width: this.props.width,
height: this.props.height,
},
);
return (
<button
onClick={ this.handleClick }
ref={ this.setWrapperRef }
width={ this.props.width }
height={ this.props.height }
>
{ Icon }
</button>);
}
}
So, I wish to add my icon to a container component. I can add it like this:
<TrashIcon fill="#fff" activeFill="#000" />
That works, but I'm OCD about styling being in my container. What I would like to do is create a styled component that pushes down those styling attributes:
// styled.js
const StyledTrashIcon = styled(TrashIcon).attrs({
fill: colors.white,
activeFill: colors.sushi,
hoverFill: colors.sushi,
})`
// other styles
`;
But when I attempt to use StyledTrashIcon
, I get:
Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
Changing to:
const StyledTrashIcon = styled(TrashIcon()).attrs({
throws this error:
Cannot create styled-component for component: [object Object]
The SVG <style> element allows style sheets to be embedded directly within SVG content. Note: SVG's style element has the same attributes as the corresponding element in HTML (see HTML's <style> element).
There are a few ways to use an SVG in a React app: Use it as a regular image. Import it as a component via bundler magic (SVGR) Include it directly as JSX.
As of styled-components v4 the withComponent API is now a candidate for deprecation. In all likelihood, you probably want to use the new "as" prop to simply switch what element/component being rendered since the withComponent API is destructive toward styles if the lowest-wrapped component is a StyledComponent.
I am now styling like this, where Arrow
is a functional component that returns an SVG:
import styled, { ThemeContext } from "styled-components";
import { Arrow } from "src/icons/Arrow";
import React, { useContext } from "react";
export const StyledArrow = () => {
const themeContext = useContext(ThemeContext);
return (
<Arrow
color={themeContext.elements.arrow.color}
width="20px"
height="20px"
/>
);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With