DEV Community

Aska
Aska

Posted on • Updated on

Customizing SVG Icon Color with React Component Using CSS Filter

When you want to dynamically change the color of svg icons, like if you're building a theme, sometimes it is difficult to dynamically pass the value especially in case you are using svg files directly exported from figma. SVG files have their preset value with fill, stroke, maybe shadow value with filter, with <g>, <circle>, <rect> ... AND different structures for each icon.

I found a stable way to implement this to svgs library using CSS filter so I'd like to share.

What is filter?

Filter is a css attribute that achieves varying visual effects (sort of like Photoshop filters for the browser). (You can see more explanation here)
Since it modifies the visible colors in svg, we do not need to modify each element (e.g. <g>, ) under <svg> element.

How do I set the hex color with filter?

This article/codepen gives a great example. By adjusting each filter value, you can achieve the appearance that looks like the desired hex color.

How can I use it with React component?

All you need is to add a way to convert the hex value to CSS filter value in your project. You could create on your own or copy a snippet from the codepen above, but this time I used this library (hex-to-css-filter) to make it easier to implement.

There are two things that you have to be careful.

  1. This library assumes the base color as #000 so if you're using white-based icons, you'll have to replace them with fill #000.
  2. If you are using React inline styling, you have to remove the semi-colon at the end of the value.

Creating React component with SVG

First, create a react component with SVG that accepts props and passes it to SVG element.

import * as React from "react";

const SvgMicOff = (props) => (
  <svg
    width="24"
    height="25"
    viewBox="0 0 24 25"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    {...props}
  >
    <path
      d="M1 2L23 24"
      stroke="black"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    />
...
  </svg>
);

export default SvgMicOff;

Enter fullscreen mode Exit fullscreen mode

In App.js, require the component and hex-to-css-filter library.

import MicOff from "../icons/mic-off";
import { hexToCSSFilter } from "hex-to-css-filter";
Enter fullscreen mode Exit fullscreen mode

Setting hex color

In the App component, create a styling passing hexColor dynamically from the state. (and make sure to remove the semi-colon!)

export default function App() {
  const [hexColor, setHexColor] = useState("#000");

  let cssFilterValue = "";
  const cssFilter = hexToCSSFilter(hexColor, {
    acceptanceLossPercentage: 1,
    maxChecks: 10
  });
  cssFilterValue = cssFilter.filter.replace(";", "");
  //semi-colon should be removed from the string
Enter fullscreen mode Exit fullscreen mode

Setting shadow

If you also want to add shadow, you could also create like so

const [shadow, setShadow] = useState("");
...
 const shadowColor =
    shadow === "dark"
      ? "drop-shadow(1px 1px 1px rgba(0,0,0,0.5))"
      : shadow === "light"
      ? "drop-shadow(1px 1px 1px rgba(255,255,255,0.5))"
      : "";
Enter fullscreen mode Exit fullscreen mode

and at last, all you have to do is to connect them as a string :)

<MicOff style={{ filter: `${cssFilterValue} ${shadowColor}` }} />
Enter fullscreen mode Exit fullscreen mode

And this is the result!

Feel free to play around, and hope this helps your development :)
Also, please let me know if you find something I can improve!

Top comments (3)

Collapse
 
feerzlay profile image
Denis Yakshov

In our projects we replace stroke and fill values with currentColor. This way we can change icon color with just one line of css.

Collapse
 
asucarlos profile image
Aska

Thanks for your reply Denis! Yes, I think for simple icons, your approach would be a better one. The reason why I tried this way was that I found for some icons that are more complex and mixing fill/stroke color (e.g. "#000", "rgba(0,0,0,0.5)" or "none"), that approach modified unwanted values. If you ever need to tackle these cases, this approach would work without problems and can be set verbose.

Collapse
 
edardev profile image
Edward Almanzar

Thank you πŸ‘πŸ‘πŸ‘