How to change VTEX IO icons
Tags: vtex, vtexio, svg
Published: 2022-08-16 20:06:00

Let's focus on #hpa-cart, or the cart icon.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eki20juqowtjl6k3jzrz.png)
 

## Step 1 - Documentation instructions
First, go to [the documentation page](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-customizing-your-stores-icons) and follow the steps to add your own `iconpack.svg` file.

#### About iconpack.svg
VTEX IO icon system is based on SVG Sprites. If you're not familiar, it's basically a big file where each SVG file is wrapped inside a Symbol (`<symbol`) or Group (`<g>`) element identified by an `id`. With this ID you can instantiate your SVG element throughout the codebase with the `<use />` element. One of the perks here is dealing with one single file download, that can even be optimized to an inline  element at top level of your document. [This CSS Tricks](https://css-tricks.com/svg-sprites-use-better-icon-fonts/) article is a good start point. 
In VTEX IO context `iconpack.svg` is the base file for the SVG Sprite system and contains all icons you'll see throughout native components. 

## Step 2 - Editing your icon
Now that you have your own version of `iconpack.svg` you can start your updates. 
SVG Sprites use IDs and identifier, so you first need the ID of the icon you want to modify. In order to grab this ID, inspect the element and look for the `<use>` element `href`. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tb3crzr39965oyrod5b.png)
 
For the cart icon, it would be `hpa-cart`. Open your `iconpack.svg` file and search for this ID. You'll replace the content of this group by the content of the SVG file of your icon. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gi551sjcbkq4vk4nw0g9.png)

Now starts the tricky part.

## Step 3 - Prepare your SVG  
In a nutshell, SVGs for VTEX IO icons need to follow at least these 3 requirements:

* `viewBox` of 16x16 
* No strokes, only fill
* No text, unless outlined.


I'll give an example using an icon from [Heroicons](https://heroicons.com/). 

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1dc7rvu4vrz953zz8c8u.png)

Heroicons offers a quick way to copy the SVG by hovering the icon on their landing page. Here's how it looks like: 

```
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
  <path stroke-linecap="round" stroke-linejoin="round" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
```
We have a few problems: 
* The viewBox is 24x24 (`0 0 24 24`)
* `<path>` uses `stroke`

Let's fix this on [Figma](https://www.figma.com/). Steps will be very similar for any other modern UI software, like XD. 


#### Fixing viewBox and SVGs styles for VTEXIO

Create a new file on your UI app or open your layout file, if you're already working with one.
In my example, I don't have a working layout file, so I'll create a new one and paste the SVG icon just to show how to set your icon.

For our working case, I'll start by converting stroke to fill using `Outline stroke`.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azhfz0u3767hqxdzbi7o.png)

Now, to fix viewBox, simply change the size of the element. Ideally, your icon should have a 1x1 aspect ration, but it might still work with a slightly different aspect ratio. In our case, I'll change the larger dimension (18, height) to 16, **toggling proportional resizing.** 
_Notice that just changing the viewBox attribute on the code will not work, since all the SVG coordinates will need to be recalculated._

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/goqaixq6j50f5bo7kxyi.png)
 
That's it for editing. Now, copy your icon as SVG (most apps will have this option, if not just export it)

#### Adding the new icon to iconpack

Paste the copied SVG into your code editor. It will look like this:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7f9q25co874lko69i1t.png)
 
Copy the inner content of the `<svg>` (but not the `svg` tag itself) and go back to `iconpack.svg`. Replace the inner content of `<g>` with the brand new code: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kjp1ynb9d3k92zvrd07e.png)

Save it and your UI should be updated with your new icon.
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/917ve0ha6pk6xd6sdb87.png)
 
#### Changing the icon color

Notice above that our new icon has an attribute `fill="black"`. That's not good and will cause troubles for theming. VTEX IO apply color on icons based on the parent element color, so in order to work as expected we need to change `fill` to `currentColor`. If your element do not have `fill` attribute, **add it**. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/syd6r421uingl5icpofr.png)

Now your icon will respond as expected to `color` attribute on the parent. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4sr2gitvqbkh2nrr811.png)

That's it. 

### FAQ 

#### My iconpack is not updating
Since `iconpack.svg` is an asset, it needs a hard-refresh to work, unlike other components that respond to hot reload. It might be the case to `unlink` and `link` again.

#### Can I add new icons?
Sure, you can create new icons. If you want to have custom icons for a [Menu](https://developers.vtex.com/vtex-developer-docs/docs/vtex-menu) item, just add them to iconpack with an ID that you'll use to reference it. I'd suggest to prefix your icon id with `custom-` or something that identify your theme. One benefit in using the icon for menu items is that `menu-item` block has it's own `viewBox` property, so it won't default to 16x16 like the rest of the icon system. 

#### What if the viewBox is not 16x16?
As the example above show, it will still work if the viewBox is slightly different, since the largest dimension is not bigger than 16. But there's a **caveat** when it comes to not 1x1 aspect ratios. Notice on the screenshot result above our icon is aligned to the left. This happened because our icon is not a perfect 1x1. If that's not tolerable and you can't have your icon drawn within a 1x1 proportion, you'll have to fix it. One possible workaround is:

Create a 16x16 rectangle; place your icon on center of this rectangle; group them; copy the SVG code of the group. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njf2ys4umzj8u0f8o06c.png)

The code will look like this. Copy all but the `<rect />` element, which is the rectangle you just created.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxpdzaf27watvfa0n47b.png)

Update your `iconpack` with it and now your icon should have more even side space. 
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxjbuecruv1wlrbzmtab.png)
 
Technically, this could be solved with a more robust approach like SVG [preserveAspectRatio](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio), but it's not possible to pass down custom attributes to SVG elements in VTEXIO. 

---

SVG can be sometimes confusing and there's plenty scenarios that will require special attention. Hope this can help you at least to get started and never use `::before` again!