Customizing SVG Icon Color with React Component Using CSS Filter
Tags: react, tutorial, css, javascript
Published: 2020-09-07 02:07:25

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)](
https://css-tricks.com/almanac/properties/f/filter/)
Since it modifies the visible colors in svg, we do not need to modify each element (e.g. `<g>`, <circle>) under `<svg>` element.

## How do I set the hex color with filter?
[This article/codepen](https://dev.to/jsm91/css-filter-generator-to-convert-from-black-to-target-hex-color-188h) gives a great example. By adjusting each filter value, you can achieve the appearance that looks like the desired hex color.

{% codepen https://codepen.io/sosuke/pen/Pjoqqp %}

## 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)](https://www.npmjs.com/package/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.

```js
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;

```

In App.js, require the component and [hex-to-css-filter](https://www.npmjs.com/package/hex-to-css-filter) library.

```js
import MicOff from "../icons/mic-off";
import { hexToCSSFilter } from "hex-to-css-filter";
```

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

```js
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
```
### Setting shadow
If you also want to add shadow, you could also create like so 
```js
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))"
      : "";
```
and at last, all you have to do is to connect them as a string :) 

```js
<MicOff style={{ filter: `${cssFilterValue} ${shadowColor}` }} />
```

And this is the result!
{% codesandbox svg-icon-color-with-hex-to-css-filter-mr19p %}

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