Replace Discourse's default SVG icons with custom icons in a theme

As of Discourse 2.3.0.beta6 (and thanks to @pmusaraj) you can now add custom SVG icons and override the defaults within a theme. You can replace a single icon, or the entire set. Here’s how:

Create an SVG Spritesheet

To get started, you must combine your SVG icons into a single spritesheet. If you have a few icons it’s easy enough to do this manually. If you have many icons, there are ways to automate this. If you’re not already familiar with some of the Grunt tools to combine SVGs, the simplest command line tool I’ve found for this is svg-sprite-generator - npm.

The spritesheet should be saved as an SVG file, and is structured like this:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="" style="display: none;">

    <symbol id="mytheme-icon-1">
      SVG code here, if you view the source of your SVG file
      this is typically everything between the <svg> tags 
      (but not the SVG tag itself, that's replaced by <symbol> above) 

    <symbol id="mytheme-icon-2">
      <!-- SVG code here -->

  • Be sure to add a custom ID to each symbol in the spritesheet. It’s probably helpful for your sanity to prefix your IDs with your theme name mytheme-icon-link.

  • Be on the lookout for style collisions within your SVGs. For example, SVGs will often have an inline style like .st0{fill:#FF0000;} defined. If you have multiple SVGs using the same classes this can cause issues (to fix these issues, edit the classes to be unique to each icon).

  • If you want to change the color of your icons via CSS, make sure any fill definitions are set to currentColor rather than a hardcoded color (like #333).

Once your spritesheet is built, you need to add theme SVG file to your theme’s asset folder and reference it as “icons-sprite” in the about.json file. For an SVG sprite called my-icons.svg, for example, your assets.json should include this:

"assets": {
   "icons-sprite": "/assets/my-icons.svg"

If you are uploading the SVG sprite through the Discourse UI, make sure you use “icons-sprite” as the SCSS var name for the upload.

Overriding default icons

Now that your spritesheet is set, you need to tell Discourse which icons to replace. This is how you do it (you can add this to your header.html file)

<script type="text/discourse-plugin" version="0.8">
  api.replaceIcon('bars', 'mytheme-icon-bars');
  api.replaceIcon('link', 'mytheme-icon-link');
  <!-- etc -->

The first ID, bars, is the default icon ID in Discourse and the second is the ID of your replacement icon. The easiest way to find an ID of one of our icons is to inspect the icon in your browser.

Here the icon name follows the d-icon- prefix. So in this example it’s d-unliked

Most of our icons follow the icon names from, but there are exceptions (which is why checking the ID in your inspector is the most reliable method). You can see all the exceptions in the const REPLACEMENTS block here on github.

That’s it. You can now style Discourse with your own custom icons!


What if you have to scale the replacements? With SVG’s that’s a little less straightforward? Or is there a recommended way to ‘pre-process’ them?


@merefield you already know this now as we’ve chatted about it, but I thought I’d reply purely as a note-to-self for when I’ve forgotten.

Insertion of SVGs seems to work more like inserting an <iframe> than an <img>. Applying size attributes through CSS doesn’t seem to work, the SVG will stay the same size and you’ll just see a smaller or larger part of it.

I found that you can control the size of the SVG ‘document’ which is inserted by adding a viewBox attribute in the SVG sprite file itself.

<svg xmlns="" style="display: none;">
    <symbol id="mycustomicon" viewBox="0 0 20 20">
        <g> (SVG code will be in here but removed for clarity) </g>

This article was helpful How to Scale SVG | CSS-Tricks.


Hello, everyone.
I replaced this icon
But it is also used elsewhere, such as here

How can I change replace the icon just for this button
Please help me solve this problem

1 Like

I have succesfully replaced some default icons in my theme:

But they appear with the same color I used in Illustrator when I created them and hovering hover them doesn’t change their color either, I thought their color for different states would be overriden by the theme colors. What could I be doing wrong?


I just changed the fill value from the HEX code I used in Illustrator to ‘currentColor’ and it seems to be working now.


Yes, that’s exactly the way to do it!

Edit: I’ve added this detail to the original post