Skip to main content
A Redmine theme is a directory inside <redmine_root>/themes/ that contains at minimum a stylesheets/application.css file. Redmine loads this stylesheet instead of the default one when the theme is selected.

Minimum required structure

themes/
└── my_theme/
    └── stylesheets/
        └── application.css      # Required — overrides the default stylesheet
A full theme may also include:
themes/
└── my_theme/
    ├── stylesheets/
    │   └── application.css      # Required
    ├── javascripts/
    │   └── theme.js             # Loaded automatically if present
    ├── images/                  # Theme-specific images
    │   └── logo.png
    └── favicon/
        └── favicon.png          # Replaces the default favicon
The directory name becomes the theme’s id. Redmine derives the display name by calling .humanize on it, so my_theme becomes My theme.

Step-by-step: create a theme

1

Create the theme directory

mkdir -p themes/my_theme/stylesheets
2

Create application.css

The simplest approach is to import the default Redmine stylesheet and then add your overrides on top. Because Redmine uses Propshaft (not Sprockets), you cannot use Sprockets-style //= require directives. Write plain CSS instead.
/* themes/my_theme/stylesheets/application.css */

/*
 * Start by importing Redmine's default stylesheet so you inherit all
 * base styles, then add your overrides below.
 *
 * Note: the exact path depends on your Redmine version and asset pipeline.
 * Inspect the default <link> tag in the rendered HTML to find the URL.
 */
@import url("/assets/application.css");

/* --- Your overrides --- */

/* Change the top bar color */
#header {
  background-color: #2c3e50;
}

/* Change link colors */
a {
  color: #2980b9;
}

a:hover {
  color: #1a5276;
}

/* Change the sidebar background */
#sidebar {
  background-color: #f4f6f7;
  border-right: 1px solid #d5d8dc;
}
3

Restart Redmine (production) or rescan (development)

In production:
bundle exec rails restart
In development, you can rescan from the Rails console:
Redmine::Themes.rescan
4

Activate the theme

  1. Go to Administration > Settings > Display.
  2. Select My theme from the Theme dropdown.
  3. Click Save.

Overriding specific styles

Use your browser’s developer tools to inspect element classes and IDs. The most commonly overridden selectors are:
SelectorWhat it controls
#headerTop navigation bar
#main-menu ulPrimary navigation links
#sidebarRight or left sidebar
#contentMain content area
#footerPage footer
.issue.status-*Issue status badges
.priority-*Issue priority indicators
table.listData tables
.flash.notice, .flash.errorFlash notification banners

Adding a custom JavaScript file

If your theme needs JavaScript (for example, to add a dark-mode toggle), create javascripts/theme.js inside your theme directory. Redmine detects the file and includes it automatically on every page:
# lib/redmine/themes.rb
def heads_for_theme
  if current_theme && current_theme.javascripts.include?('theme')
    javascript_include_tag current_theme.javascript_path('theme')
  end
end
// themes/my_theme/javascripts/theme.js
document.addEventListener('DOMContentLoaded', function () {
  // Example: add a class to the body for conditional CSS
  document.body.classList.add('my-theme-active');
});

Replacing images

Place image files in themes/my_theme/images/. To reference them in your CSS:
/* The asset_prefix for a theme is themes/<dir>/ */
#header .logo {
  background-image: url("../images/logo.png");
}

Custom favicon

Place a favicon file in themes/my_theme/favicon/. Redmine picks up the first file found in that directory:
# lib/redmine/themes.rb
def favicon
  favicons.first
end
themes/my_theme/
└── favicon/
    └── favicon.png
The favicon is served at the path themes/my_theme/favicon/favicon.png.

Theme identification

Redmine uses the directory name as the theme’s unique identifier. The Theme class provides:
# lib/redmine/themes.rb
class Theme
  attr_reader :path, :name, :dir

  def initialize(path)
    @path = path
    @dir  = File.basename(path)
    @name = @dir.humanize   # "my_theme" => "My theme"
  end

  # Directory name used as the theme id
  def id; dir end
end
Choose a directory name that is unique and descriptive. Avoid spaces and special characters — use underscores instead.

Troubleshooting

Verify that themes/my_theme/stylesheets/application.css exists. Redmine silently ignores directories that do not contain this file. If you added the theme while Redmine was running in production, restart the server.
Theme images are served from themes/<dir>/images/. Check that your CSS url() paths are relative to the stylesheet file, or use the absolute path /themes/my_theme/images/<filename>.
In production mode, assets may be cached. Run bundle exec rake assets:precompile or perform a hard refresh in the browser. In development mode, the asset pipeline serves files directly so changes should appear immediately.
Browsers cache favicons aggressively. After updating the file, open a new browser tab or clear the browser cache.