Introduction

According to Microsoft documentation, you can use a base64-encoded image for your web part icons. However, base64-encoded SVG images -- as is shown in the documentation -- don't work as expected. And by the looks of it, this hasn't worked for a while.

Since the SPFx team has been working tirelessly to deliver more than 15 releases of SPFx since its general availability, I'm sure we can forgive them for letting something so minor fall through the cracks.

However, I really don't like how icons that were converted from PNG look slightly blurry. (I tend to obsess about little things like that sometimes).

As I was writing another post for my SharePoint Framework Design series, I decided to get to the bottom of the issue.

As it turns out, it was pretty easy to solve.

TL;DR

This is an interactive post: we'll convert your SVG so that you can use it as an SPFx web part icon.

If you don't care about the explanation, you can go straight to the solution

The Challenge

My challenge was that I wanted to use SVG images in my web part's manifest, but I didn't want to have a separate SVG asset. I wanted to define a base64-encoded SVG file, as is demonstrated in the SharePoint documentation.

I knew it didn't work (believe me, I've tried), so I wanted a solution that would not rely on any unsupported hacks.

Since I don't have access to change the SharePoint code, I needed a solution that would work without requiring any changes from SharePoint.

How SPFx web part icons work

According to the Microsoft documentation, for your SPFx web part icon you can use either an Office UI Fabric icon, an external icon image, or a base64-encoded image.

To change your icon to an Office UI Fabric icon, you simply open your web part's [YourWebPartName].manifest.json and change the "officeFabricIconFontName" node to the name of the icon you want from the UI Fabric site.

The default icon is Page. If you wanted to change your icon to the Sunny icon, you would simply change the following line:

"officeFabricIconFontName": "Page",

To this:

"officeFabricIconFontName": "Sunny",

Note that you have to re-build the web part (run gulp build) and reload your workbench (press [F5] on your keyboard) before you'll see the new icon. Trust me, I wasted a lot of time trying to figure out why my new icons weren't showing up.

If you want to set the icon to an external image, you'll want to find the URL of a publicly-accessible image and change your web part's manifest "officeFabricIconFontName" attribute from the following:

"officeFabricIconFontName": "Page",

For a "iconImageUrl" image URL, as follows:

 "iconImageUrl": "https://assets.contoso.com/weather.png",

You can also use a CDN, or use your SharePoint CDN to store your images.

If you don't want to use an external image, you'll want to use a base64-encoded image.

To do so, you'll have to first convert your image using a tool like this web site. Once you have your base64-encoded image, you'll change your web part's manifest from this:

"officeFabricIconFontName": "Page",

To this:

 "iconImageUrl": "data:...",

And you would put the entire base64-encoded string as the web part's URL. Because you see, the base64-encoded string is actually a valid URL.

It is just a special kind of URL, called a data URI.

About data URI

Base64-encoded images, whether they are SVG or PNG, JPG, or GIF, rely on data URI. Data URI allow you to embed a resource in a URI which would normally result in a separate HTTP request.

Most data URI consists of the data type of the item (e.g.: image/png), followed by a semicolon, and the data of that file.

The cool thing about data URI is that -- on most modern browsers -- you can pretty much use them anywhere you would normally use a link to a resource.

Parker

For example, to show the above image of Parker in HTML, you would embed an img element and point the src attribute to the URL of the image, as follows:

<img src="https://avatars0.githubusercontent.com/u/31443929?s=200&v=4" />

Using a data URI, you could also do this:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAABpUUlEQVR4nOxdBVgU2xc/S3d3d0iDtKgI2N3d+tBnd+uzu7D924mJGIgoIAooKiGIIp1KLsvS+f/mbrAxu+xiofL75JvZmTt3Ztd75vQ5Qi0tLdCJTnQCHwK/+gE60YmOjE4C6...

Which produces this image:

The first version of this image had a URL pointing to the original source of the image, while the second one contained the actual image!

To generate the super-long gibberish, I used this online base64-encoder and uploaded a copy of Parker's avatar, then copied that super-long string it generated into the src attribute of my img tag.

You have to base64-encode the image because you're trying to embed a binary file inside of HTML.

Except that SVG files are not binaries...

Using data URI without base64-encoding

SVG files are simply text markup files, like HTML.

During my research, I found an article entitled Probably don't base64 SVG which explains that when you base64-encode an image...

"It takes 4 characters per 3 bytes of data, plus potentially a bit of padding at the end."

Essentially, base64-encoding SVG takes more room than the original file! Files are essentially 133% bigger!

Fortunately, you can actually use your UTF-8 encoded SVG file inside a data URI as follows:

<img src="data:image/svg+xml; ... ">

Now, you need to make sure that you don't embed unsupported characters inside your src attribute. For example, if your SVG has a single quote (') and your src attribute uses single-quotes to define it, you'll want to escape the '.

Fortunately, Taylor Hunt wrote a great article explaining how to encode SVGs in data URI while optimizing them to help you with that.

Taylor's awesome article inspired someone to write a codepen to encode SVGs.

I forked Jakob-e's codepen to make my own which makes it easy to encode SVGs to work as a data URI icon for a web part's manifest.

Using a data URI SVG as your icon

To use your custom SVG as an icon, take the following steps:

  1. Design an icon so that it fits within a square, ideally 64x64, or at least 32x32.

  2. Make sure that your icon <svg> element sets the width and height attributes -- otherwise, your icon will be cropped and/or will not appear centered. To do so, simply change your SVG opening tag from:

    <svg>

    To this:

    <svg height="64" width="64">
  3. Consider optimizing your SVG by using SVGOMG or a similar tool.

  4. Paste your SVG in the box below to encode your SVG

VariableValue
Original SVG

  1. In your web part's [YourWebPartName].manifest.json, change the following line:

    "officeFabricIconFontName": "Page",

    To this:


    Don't forget the extra , at the end of the line.

  2. Rebuild your web part by running gulp build
  3. Refresh your workbench

Your new SVG icon should appear!

Conclusion

You still can't use base64-encoded icons as your web part icon -- at that's probably a good thing, because base64-encoded SVG files are bigger! -- but you can use a data URI image instead.

This article shows you how to convert your SVG so that it will produce beautiful web part icons.

Regardless of whether Microsoft ever fixes the issue with SVG icons for web parts, you should still consider optimizing your SVG before using it in your solutions.

I hope this helps?

Updates

  • September 1, 2019: This approach will also work for application extension.

Sources

Author

Independent consultant. Certified SCRUM Master. SharePoint, Office 365 and Dynamics 365 are his favourite toys.

How can I help?

This site uses Akismet to reduce spam. Learn how your comment data is processed.