Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 916
JasonGenX Avatar asked Jun 20 '19 19:06

JasonGenX


People also ask

How change SVG color React?

To change the color of an SVG in React:Import the SVG as a component. Set the fill and stroke props on the component, e.g. <MyLogo fill="black" stroke="yellow" /> .

How can you apply dynamic styles to styled components?

One way to dynamically change css properties with styled components is to insert a custom prop into your React component and access said property using the dollar sign and curly braces commonly used for template literals. Our current example is testing to see if our use pointer prop is true.


3 Answers

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.

like image 109
JasonGenX Avatar answered Nov 20 '22 21:11

JasonGenX


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

like image 34
Harley Lang Avatar answered Nov 20 '22 20:11

Harley Lang


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} />)
like image 29
Anton Nevsgodov Avatar answered Nov 20 '22 22:11

Anton Nevsgodov