Adding SVG Icons to a Redmine 6+ Plugin

Redmine 6+ has switched to using SVG sprites for icons instead of traditional PNGs. This improves performance, reduces the number of HTTP requests, and simplifies icon management.

This document explains how to correctly add SVG icons to a plugin, following Redmine's official recommendations.


1. Using Standard Redmine Icons

Before adding custom icons to a plugin, it is recommended to use the built-in Redmine SVG icons.
This can be done using the sprite_icon method:

<%= sprite_icon('pencil', l(:button_edit)) %>
<%= sprite_icon('plus', l(:button_add)) %>
<%= sprite_icon('trash', l(:button_delete)) %>

This method automatically uses icons.svg from Redmine.

Important! Some icons, such as add, delete, copy, edit, already exist in Redmine’s global sprite. These should be used without specifying the plugin to avoid duplication:

<%= sprite_icon('add', l(:button_add)) %>
<%= sprite_icon('delete', l(:button_delete)) %>
<%= sprite_icon('copy', l(:button_copy)) %>

If the plugin parameter is specified, Redmine will look for these icons in the plugin sprite, even though they already exist in Redmine's default set, making their recreation unnecessary.


2. Adding Custom Icons to a Plugin

Step 1: Creating config/icon_source.yml

To use additional icons, create the config/icon_source.yml file inside the plugin folder.
This file allows downloading SVG icons from Tabler Icons and automatically including them in the sprite.

Example config/icon_source.yml:

# This file is used by icons rake task to download SVG icons from Tabler
# Keys description:
#   - name: destination icon name (used in sprite_icon)
#     svg: source icon name from Tabler Icons
#     style: outline (default) or filled

- name: custom-icon
  svg: star
- name: reload
  svg: refresh

- name — the icon name used in sprite_icon.
- svg — the original icon name from Tabler Icons.
- style — an optional parameter (outline or filled).


Step 2: Generating icons.svg for the Plugin

After setting up config/icon_source.yml, run the following command:

rake icons:plugin:generate NAME=<redmine_plugin_name>
This command:
  1. Downloads the required icons from Tabler Icons.
  2. Creates icons.svg in public/plugin_assets/<redmine_plugin_name>/images/.
  3. Generates an SVG sprite that can be used in templates.

After running the command, check the contents of icons.svg and manually edit it if needed.


Step 3: Using Custom Icons in Templates

After generating icons.svg, icons can be used in plugin templates:

<%= sprite_icon('custom-icon', plugin: :<redmine_plugin_name>) %>
<%= sprite_icon('reload', plugin: :<redmine_plugin_name>) %>

Important! The plugin parameter should be used only for custom icons that are not included in Redmine’s default set.


3. CSS Rules for PNG Icon Compatibility

For backward compatibility with CSS classes that used PNG files, update the CSS.
Use :not(:has(svg)) to ensure PNGs are only displayed when an SVG is unavailable.

Example app/assets/stylesheets/<redmine_plugin_name>.css:

.icon-edit:not(:has(svg)) { background-image: url(../images/pencil.png); }
.icon-add:not(:has(svg)) { background-image: url(../images/circle-plus.png); }
.icon-copy:not(:has(svg)) { background-image: url(../images/copy.png); }
.icon-del:not(:has(svg)) { background-image: url(../images/trash.png); }

If the browser does not support :has(), use JavaScript to remove background-image from elements containing <svg>:

document.querySelectorAll('.icon').forEach(icon => {
  if (icon.querySelector('svg')) {
    icon.style.backgroundImage = 'none';
  }
});

4. Additional Rake Tasks for Icon Management

Command Description
rake icons:download Downloads Redmine's default icons
rake icons:generate Downloads icons and generates an SVG sprite
rake icons:plugin:download Downloads SVG icons for a plugin
rake icons:plugin:generate Downloads icons and generates a sprite for a plugin
rake icons:plugin:sprite Generates only a sprite for the plugin
rake icons:sprite Generates a general SVG sprite

Use rake icons:plugin:generate NAME=<redmine_plugin_name> to update the sprite.


5. Support for Older Versions of Redmine

For backward compatibility with Redmine 5 and earlier, where sprite_icon may be missing, use a compatibility patch from redmineup gem.

Adding Compatibility in init.rb

require 'redmineup/patches/compatibility_patch'

This patch automatically adapts icon handling for older versions of Redmine.


6. Common Errors and Solutions

Error Solution
Icon does not display Ensure that plugin: :<redmine_plugin_name> is specified in sprite_icon if using a custom plugin icon.
Icon was not added to icons.svg Check that config/icon_source.yml contains valid entries and rerun rake icons:plugin:generate.
Changes to icons.svg are not applied Run rake assets:precompile to rebuild assets.
Old PNG icons are still displayed Add :not(:has(svg)) to CSS to disable background-image when an SVG is present.

Conclusion

  1. Use standard Redmine icons without plugin to avoid duplication.
  2. Create config/icon_source.yml and define custom icons.
  3. Generate icons.svg using rake icons:plugin:generate.
  4. Use sprite_icon('custom-icon', plugin: :<redmine_plugin_name>) only for new icons.
  5. Add a CSS filter :not(:has(svg)) to disable old PNG icons.
  6. Rebuild assets using rake assets:precompile.
  7. For compatibility, include compatibility_patch.

Following these recommendations will ensure correct SVG icon rendering in your plugin and maintain compatibility with Redmine 6+.

Was this helpful? Yes No Added by Kirill Bezrukov about 2 months ago. Updated about 2 months ago.