diff --git a/docbook/reference/en/en-US/modules/themes.xml b/docbook/reference/en/en-US/modules/themes.xml
index 3996b3a0b05..db3d659a48b 100755
--- a/docbook/reference/en/en-US/modules/themes.xml
+++ b/docbook/reference/en/en-US/modules/themes.xml
@@ -2,18 +2,18 @@
Themes
- Keycloak provides theme support for login forms and account management. This allows customizing the look
- and feel of end-user facing pages so they can be integrated with your brand and applications.
+ Keycloak provides theme support for web pages and emails. This allows customizing the look
+ and feel of end-user facing pages so they can be integrated with your applications.
Theme types
- There are several types of themes in Keycloak:
+ A theme can support several types to customize different aspects of Keycloak. The types currently available
+ are:
Account - Account management
Admin - Admin console
- Common - Shared resources for themes
Email - Emails
Login - Login forms
Welcome - Welcome pages
@@ -28,6 +28,11 @@
the theme used for a realm open the Keycloak Admin Console, select your realm
from the drop-down box in the top left corner. Under Settings click on Theme.
+
+ To set the theme for the master Keycloak admin console set the admin console theme for
+ the master realm. To set the theme for per realm admin access control set the admin console
+ theme for the corresponding realm.
+
To change the welcome theme you need to edit standalone/configuration/keycloak-server.json
and add welcomeTheme to the theme element, for example:
@@ -43,9 +48,8 @@
Default themes
- Keycloak comes bundled with default themes in standalone/configuration/themes. It is
- not recommended to edit these themes directly. Instead you should create a new theme to extend a default
- theme. A good reference is to copy the keycloak themes as these extend the base theme to add styling.
+ Keycloak comes bundled with default themes in standalone/configuration/themes. You should
+ not edit the bundled themes directly. Instead create a new theme that extends a bundled theme.
@@ -65,24 +69,63 @@
A theme can extend another theme. When extending a theme you can override individual files (templates, stylesheets, etc.).
The recommended way to create a theme is to extend the base theme. The base theme provides templates
- and a default message bundle. It should be possible to achieve the customization required by styling these
- templates.
+ and a default message bundle. If you decide to override templates bear in mind that you may need to update
+ your templates when upgrading to a new release to include any changes made to the original template.
- To create a new theme, create a folder in .../standalone/configuration/themes/<theme type>.
- The name of the folder is the name of the theme. Then create a file theme.properties inside the theme folder.
- The contents of the file should be:
+ Before creating a theme it's a good idea to disable caching as this makes it possible to edit theme resources
+ without restarting the server. To do this open ../standalone/configuration/keycloak-server.json
+ for theme set staticMaxAge to -1 and
+ cacheTemplates and cacheThemes to false. For example:
+[
+ Remember to re-enable caching in production as it will significantly impact performance.
- parent=base
- You have now created your theme. Check that it works by configuring it for a realm. It should look the same
- as the base theme as you've not added anything to it yet. The next sections will describe how to modify
- the theme.
+ To create a new theme create a directory for the theme in .../standalone/configuration/themes.
+ The name of the directory should be the name of the theme. For example to create a theme called example-theme
+ create the directory .../standalone/configuration/themes/example-theme. Inside the theme
+ directory you then need to create a directory for each of the types your theme is going to provide. For example
+ to add the login type to the example-theme theme create the directory
+ .../standalone/configuration/themes/example-theme/login.
+
+
+ For each type create a file theme.properties which allows setting some configuration for
+ the theme, for example what theme it overrides and if it should import any themes. For the above example we
+ want to override the base theme and import common resources from the Keycloak theme. To do this create the
+ file .../standalone/configuration/themes/example-theme/login/theme.properties with the
+ following contents:
+[
+
+
+ You have now created a theme with support for the login type. To check that it works open the admin console.
+ Select your realm and click on Themes. For Login Theme select
+ example-theme and click Save. Then open the login page for the realm.
+ You can do this either by login through your application or by opening http://localhost:8080/realms/<realm name>/account.
+
+
+ To see the effect of changing the parent theme, set parent=keycloak in theme.properties
+ and refresh the login page. To follow the rest of the documentation set it back to parent=base
+ before continuing.
+
Stylesheets
- A theme can have one or more stylesheets, to add a stylesheet create a file inside resources/css (for example resources/css/styles.css)
- inside your theme folder. Then registering it in theme.properties by adding:
+ A theme can have one or more stylesheets, to add a stylesheet create a file inside resources/css
+ (for example resources/css/styles.css) inside your theme folder. Then registering it
+ in theme.properties by adding:
styles=css/styles.css
@@ -90,6 +133,17 @@
as you want. For example:
styles=css/styles.css css/more-styles.css
+ For the example-theme above add example-theme/login/resources/css/styles.css with the
+ following content:
+[
+ Then edit example-theme/login/theme.properties and add styles=css/styles.css.
+ Refresh the login page to see your changes. It's not pretty, but you can see how easily you can modify the
+ styles for your theme.
Scripts
@@ -121,9 +175,8 @@
Messages
- Text in the templates are loaded from message bundles. Currently internationalization isn't supported,
- but that will be added in a later release. A theme that extends another theme will inherit all messages
- from the parents message bundle, but can override individual messages. For example to replace
+ Text in the templates are loaded from message bundles. A theme that extends another theme will inherit
+ all messages from the parents message bundle, but can override individual messages. For example to replace
Username on the login form with Your Username create the file
messages/messages.properties inside your theme folder and add the following content:
@@ -134,30 +187,79 @@
Keycloak uses Freemarker Templates in order to generate HTML.
These templates are defined in .ftl files and can be overriden from the base theme.
- Check out the Freemarker website on how to form a template file.
+ Check out the Freemarker website on how to form a template file. To override the login template for the
+ example-theme copy ../standalone/configuration/themes/base/login/login.ftl
+ to ../standalone/configuration/themes/example-theme/login and open it in an editor. After
+ the first line (<#import ...>) add <h1>HELLO WORLD!</h1> then refresh
+ the page.
+
+ Deploying themes
+
+ Themes can be deployed to Keycloak by copying the theme directory to ../standalone/configuration/themes
+ or it can be deployed as a module. For a single server or during development just copying the theme is fine, but
+ in a cluster or domain it's recommended to deploy as a module.
+
+
+ To deploy a theme as a module you need to create an jar (it's basically just a zip with jar extension) with
+ the theme resources and a file META/keycloak-server.json that describes the themes contained
+ in the archive. For example example-theme.jar with the contents:
+
+ META-INF/keycloak-themes.json
+ theme/example-theme/login/theme.properties
+ theme/example-theme/login/login.ftl
+ theme/example-theme/login/resources/css/styles.css
+
+ The contents of META-INF/keycloak-server.json in this case would be:
+[
+ As you can see a single jar can contain multiple themes and each theme can support one or more types.
+
+
+ The deploy the jar as a module to Keycloak you can either manually create the module or use jboss-cli.
+ It's simplest to use jboss-cli as it creates the required directories and module descriptor
+ for you. To deploy the above jar jboss-cli run:
+[
+ If you're on windows run KEYCLOAK_HOME/bin/jboss-cli.bat.
+
+
+ This command creates modules/org/example/exampletheme/main containing example-theme.jar
+ and module.xml.
+
+
+ Once you've created the module you need to register it with Keycloak do this by editing
+ ../standalone/configuration/keycloak-server.json and adding the module to theme/module/modules. For example:
+[
+
+
+ If a theme is deployed to ../standalone/configuration/themes and as a module the first
+ is used.
+
+
+
SPIs
For full control of login forms and account management Keycloak provides a number of SPIs.
-
- Theme SPI
-
- The Theme SPI allows creating different mechanisms to load themes for the default FreeMarker based
- implementations of login forms and account management. To create a theme provider you will need to implement
- org.keycloak.freemarker.ThemeProviderFactory and org.keycloak.freemarker.ThemeProvider.
-
-
- Keycloak comes with two theme providers, one that loads themes from the classpath (used by default themes)
- and another that loads themes from a folder (used by custom themes). Looking at these
- would be a good place to start to create your own theme provider. You can find them inside
- forms/common-themes on GitHub or the source download.
-
-
Account SPI
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
index 2fdaf0513cb..42fa50e3610 100755
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
@@ -11,9 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class ExtendingThemeManagerFactory implements ThemeProviderFactory {
- private ConcurrentHashMap themeCache = new ConcurrentHashMap();
-
- private ExtendingThemeManager themeManager;
+ private ConcurrentHashMap themeCache;
@Override
public ThemeProvider create(KeycloakSession session) {
@@ -23,7 +21,7 @@ public class ExtendingThemeManagerFactory implements ThemeProviderFactory {
@Override
public void init(Config.Scope config) {
if(Config.scope("theme").getBoolean("cacheThemes", true)) {
- themeCache = new ConcurrentHashMap();
+ themeCache = new ConcurrentHashMap<>();
}
}
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
index 8f2dc0e534b..e41d671c28a 100755
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
@@ -20,7 +20,7 @@ public class FreeMarkerUtil {
public FreeMarkerUtil() {
if (Config.scope("theme").getBoolean("cacheTemplates", true)) {
- cache = new ConcurrentHashMap();
+ cache = new ConcurrentHashMap<>();
}
}
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java b/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
index 0edc92ee5fb..7d9ce2abb8a 100644
--- a/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
@@ -18,11 +18,13 @@ public class FolderTheme implements Theme {
private String parentName;
private String importName;
private File themeDir;
+ private String name;
private Type type;
private final Properties properties;
- public FolderTheme(File themeDir, Type type) throws IOException {
+ public FolderTheme(File themeDir, String name, Type type) throws IOException {
this.themeDir = themeDir;
+ this.name = name;
this.type = type;
this.properties = new Properties();
@@ -36,7 +38,7 @@ public class FolderTheme implements Theme {
@Override
public String getName() {
- return themeDir.getName();
+ return name;
}
@Override
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
index df653699bb4..90d8ba66bf0 100755
--- a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
@@ -29,7 +29,7 @@ public class FolderThemeProvider implements ThemeProvider {
@Override
public Theme getTheme(String name, Theme.Type type) throws IOException {
File themeDir = getThemeDir(name, type);
- return themeDir.isDirectory() ? new FolderTheme(themeDir, type) : null;
+ return themeDir.isDirectory() ? new FolderTheme(themeDir, name, type) : null;
}
@Override