Mitchell Hillman

Launching React from a Keycloak theme

Keycloak is highly themable using freemarker templates. But I need more than that to support a shared library of UI components used in the rest of my application. The solution is to use a window.CONFIG object to provide theme values to a React application which is launched from registrationLayout template. The React application can then use the shared components at build time.

Template files

A react-template.ftl layout is created in the keycloak theme. This is root level HTML for the theme and has markup for mounting the React application.


<#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true>
  <!DOCTYPE html>
  <html lang="en">
    <title>App Name</title>
    <meta charset="utf-8"/>
    <link rel="icon" href="${url.resourcesPath}/img/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <link href="${url.resourcesPath}/css/reset.css" rel="stylesheet">
    <script defer="defer" src="${url.resourcesPath}/js/main.a9c8f6d7.js"></script>
    <#nested "form">
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>

Note the <#nested "form"> inside the <head> tag

Each themed page in keycloak is a simple template which only defines its parent layout and sets the theme values to an object created in global scope.


<#import "react-template.ftl" as layout>
<@layout.registrationLayout displayInfo=true; section>
  <#outputformat "HTML">
      window.CONFIG = {
        resourceUrl: "${url.resourcesPath}",
        loginAction: "${url.loginAction?no_esc}",
        forgetPasswordUrl: "${url.loginResetCredentialsUrl}",
        <#if !usernameHidden??>
          usernameHidden: false,
          usernameHidden: true,
        <#if message?has_content>
          message: {
            summary: '${message.summary}',
            type: '${message.type}',
        env: "theme"



"build": "react-scripts build && bash",

This example assumes Create React App as a starting point for the React app, hence the react-scripts for the build. The important point to note is that the custom is called after the react app is built.

#!/usr/bin/env bash

# copy app resources to theme folder
rm -rf $pathToResources
cp -r ./build/static $pathToResources

# get hash from the built index.html
build="$(cat build/index.html)"
if [[ $build =~ $regex ]]; then

# replace hash in react-template.ftl
template="$(cat ./keycloak/themes/lsm/login/react-template.ftl)"
if [[ $template =~ $regex ]]; then
echo "$new" > "./keycloak/themes/lsm/login/react-template.ftl"