How to use custom SVG icons for your Gutenberg blocks

By default when you run npx @wordpress/create-block you’ll get a preformed block with a smiley face icon like this:

Smiley faced default icon in a custom Gutenberg block.

In the method of Guteberg block registration that the NPM @wordpress/create-block uses the arguments are stored in JSON at in block.json.

Gutenberg block icon defined in block.json

One option worth mentioning is that you can use any of the available dashicons for your custom Gutenberg block simply by changing the specified icon name. Underneath the hood the dashicons are loaded into React using their SVG’s rather than the regular dashicon icon font. And this is why we can use the same approach to swap in a custom SVG icon.

In this example shown below I’m overriding the definition of “icon” in block.json and specifying it in the index.js file as an argument for the registerBlockType(). While I’m still using a dashicon in this example, this is the first step towards supporting a custom SVG icon for our Gutenberg block. What we’ll do next is make an SVG element and pass it here in place of the dashicon named icon. The registerBlockType() function is checking for either option and will handle the rest.

Specifying a dashicon icon in JS registerBlockType().

For my project I headed over to FontAwesome where I have a premium account and picked out an icon that I think works well for a “team” of people, it’s actually designed to represent students in a classroom but I think it works well for this purpose also. I exported the SVG and imported it into Figma where I swapped the colors:

Coloring an SVG from FontAwesome in Figma for use in Gutenberg!

After exporting the SVG from Figma I drop the file into the block I’m working on and open it in my editor (Atom). We won’t actually use the SVG file, instead we’ll be taking the definition of the SVG path found the variable “d”.

The screenshot below shows the critical part of the solution. First we load “createElement” from WordPress React element and then we use it to create our SVG element. The SVG element is really 2 different elements, a path tag nested inside the svg tag. Hopefully you have good copy and paste skills (arguably the most important skill for any developer). You’ll to get the “d” path from your SVG file and make sure you don’t get any other part of the tag. For large SVG definitions pro tip is to zoom out a lot to make the selection of the long text easier.

If you’re block stops loading or you don’t see the icon loading start your troubleshooting by looking for any Javascript errors in the console. Check if the NPM build process worked, and if it did then try refreshing Gutenberg and checking for your SVG in it’s usual position.

Here is how it turned out after my initial render of the custom SVG in the Saber Teams Gutenberg block:

Custom SVG icon rendered in a Gutenberg block.

If you’re really observant you might be able to see that the positioning of the icon seems just slightly off. It’s 2.5px off to be exact. That’s because the Gutenberg editor wants the icon to be 20×20 but this icon I’ve used is 20×15. The box it sits in is still 20×20 and it renders from the top causing it to look like it’s about 2.5px higher than it should be. The only solution… is to entirely rebuilt Gutenberg.

Next I head back into Figma to adjust the icon and make it 20×20. One option is to put a background 20×20 behind the icon and then vertically center the icon into it.

As I tinkered around in Figma I added a solid line under the icon to give it a bit more height and because I thought it adds something to the icon as well. I then experimented with a black background, let’s see how much this would stand out in Gutenberg?

Customizing our SVG for the Gutenberg block in Figma.

I realized after exporting and updating the code that the black background did not show up unless I use the fill parameter. It’s a really useful thing to make SVG elements (or any elements) this way because it opens up a lot of interesting possibilities. Here is what I ended up with after trying a few different design variations:

Similar Posts