Using Styled Components to change the color of an SVG's stroke

16,114

Solution 1

So I looked into this. Turns out you cannot CSS style an SVG image you're loading using the <img> tag.

What I've done is this:

I inlined my SVG like this:

 <BurgerImageStyle x="0px" y="0px" viewBox="0 0 38 28.4">
      <line x1="0" y1="1" x2="38" y2="1"/>
      <line x1="0" y1="14.2" x2="38" y2="14.2"/>
      <line x1="0" y1="27.4" x2="38" y2="27.4"/>
 </BurgerImageStyle>

Then I used Styled Components to style BurgerImageStyle:

const BurgerImageStyle = styled.svg`
    line {
      stroke: black;
    }    
    &:hover {
      line {
        stroke: purple;
      }
    }     
`;

This worked.

Solution 2

If you are looking to avoid writing separate components or copying your raw SVG file, consider react-inlinesvg;

https://github.com/gilbarbara/react-inlinesvg

import React from "react";
import styled from "styled-components";
import SVG from "react-inlinesvg";
import radio from "./radio.svg";

interface SVGProps {
  color: string;
}

const StyledSVG = styled(SVG)<SVGProps>`
  width: 24px;
  height: 24px;
  & path {
    fill: ${({ color }) => color};
  }
`;

export default function App() {
  const color = "#007bff";
  return <StyledSVG color={color} src={radio} />;
}

Code Sandbox: https://codesandbox.io/s/stack-56692784-styling-svgs-iz3dc?file=/src/App.tsx:0-414

Solution 3

If you want to have some styling shared across multiple SVGs and you don't want to have an extra dependency on react-inlinesvg you can use this thing instead:

In src prop it accepts SVG React component

import styled from 'styled-components';
import React, { FC, memo } from 'react';

type StyledIconProps = {
  checked?: boolean;
};

const StyledIconWrapper = styled.div<StyledIconProps>`
  & svg {
    color: ${(p) => p.checked ? '#8761DB' : '#A1AAB9'};
    transition: 0.1s color ease-out;
  }
`;

export const StyledIcon = memo((props: StyledIconProps & { src: FC }) => {
  const { src, ...rest } = props;

  const Icon = src;

  return (
    <StyledIconWrapper {...rest}>
      <Icon/>
    </StyledIconWrapper>
  );
});

And then you can use it like:

import { StyledIcon } from 'src/StyledIcon';
import { ReactComponent as Icon } from 'assets/icon.svg';

const A = () => (<StyledIcon src={Icon} checked={false} />)
Share:
16,114

Related videos on Youtube

JasonGenX
Author by

JasonGenX

My passion is solving real world problems with code. Always learning new languages/frameworks - hence why I'm here.

Updated on June 04, 2022

Comments

  • JasonGenX
    JasonGenX almost 2 years

    I have an SVG I'm using as an <img> tag. Using Styled Components I am trying to get to a point where I change the stroke color upon hover.

    I imported the SVG:

    import BurgerOpenSvg from '../../images/burger_open.svg';
    

    I Created a Styled Components for it:

       const BurgerImageStyle = styled.img`
        &:hover {     
            .st0 {
              stroke: red;
            }
        }
    `;
    

    And I use it:

    <BurgerImageStyle alt="my-burger" src={BurgerOpenSvg}/>     
    

    The result is, my SVG is displayed correctly, but no color change upon hovering.

    Source for the SVG I use:

    <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 38 28.4" style="enable-background:new 0 0 38 28.4;" xml:space="preserve">
    <style type="text/css">
        .st0{fill:none;stroke:#221f1f;stroke-width:2;stroke-miterlimit:10;}
    </style>
    <g>
        <g id="XMLID_7_">
            <line class="st0" x1="0" y1="1" x2="38" y2="1"/>
        </g>
        <g id="XMLID_6_">
            <line class="st0" x1="0" y1="14.2" x2="38" y2="14.2"/>
        </g>
        <g id="XMLID_5_">
            <line class="st0" x1="0" y1="27.4" x2="38" y2="27.4"/>
        </g>
    </g>
    </svg>
    

    The SVG Renders as follows:

    enter image description here

    Is it even possible to update the class on an SVG loaded in an <img> tag? or must it be inline <svg> tag?