Keycloakify - Keycloak UI customization
# clone project
git clone https://github.com/keycloakify/keycloakify-starter
git remote set-url origin git@gitlab.com:{gitlab-group}/keycloak-theme-tps.git # change git remote to your gitlab group
# install dependencies
cd keycloakify-starter/
bun install
# preview UI with storybook
bun --bun run storybook
# start keycloak docker server
sudo apt-get install maven
bunx keycloakify start-keycloak
# add or eject page
bunx keycloakify add-story # Select login.ftl (for example)
bunx keycloakify eject-page
bunx keycloakify initialize-account-theme
bun install -d tailwindcss postcss autoprefixer prettier-plugin-tailwindcss
Create main.css file in src/login/, then import in src/login/KcPage.tsx
Run storybook to preview UI. Find class in coresponding component and customize it to main.css file. See tutorial in https://docs.keycloakify.dev/css-customization
If you want to customize login page, you must eject it first
bunx keycloakify eject-page
// src/login/KcPage.tsx
const LoginUpdatePassword = lazy(() => import('./pages/LoginUpdatePassword'));
...
switch (kcContext.pageId) {
case 'login.ftl':
return <Login {...{ kcContext, i18n, classes }} Template={Template} doUseDefaultCss={false} />;
case 'login-update-password.ftl':
return (
<LoginUpdatePassword {...{ kcContext, i18n, classes }} Template={Template} doUseDefaultCss={false} />
);
// tailwind.config.js
export default {
theme: {
extend: {
backgroundImage: {
'img-logo': "url('./assets/images/logo.png')",
'img-logo-slogan': "url('./assets/images/logo-slogan.png')",
},
},
},
};
.kcHeaderWrapperClass {
@apply size bg-img-logo bg-contain bg-no-repeat;
@apply text-transparent !important;
}
woff2) file into folder src/login/assets/fonts. Example: Material Icons SharpIf you want to optimize font file size, import svg from google font icon using icomoon, then export to font file (woff and tff)
Add some code
// tailwind.config.js
export default {
theme: {
extend: {
fontFamily: {
'material-icons': ['Material Icons Sharp']
},
}
}
}
/* main.css */
@font-face {
font-family: 'Material Icons Sharp';
/* src: url('./assets/fonts/MaterialSymbolsSharp[FILL,GRAD,opsz,wght].woff2') format('woff2'); */
src:
url('./assets/fonts/font.woff') format('woff'),
url('./assets/fonts/font.tff') format('truetype');
}
// Add icons user and visibility to login form
.usernameIcon,
.kcFormPasswordVisibilityIconHide,
.kcFormPasswordVisibilityIconShow {
@apply absolute right-4 top-[2.6rem] font-material-icons text-xl not-italic;
font-variation-settings:
'FILL' 0,
'wght' 300,
'GRAD' 0,
'opsz' 48;
}
.usernameIcon::after {
content: '\e7fd'; /* person */
@apply text-2xl;
}
.kcFormPasswordVisibilityIconHide::after {
content: '\e8f5'; /* visibility_off */
}
.kcFormPasswordVisibilityIconShow::after {
content: '\e8f4'; /* visibility */
}
...
Change theme name
// src/kc.gen.tsx
export type ThemeName = 'keycloakify-starter';
export type ThemeName = 'tps';
export const themeNames: ThemeName[] = ['keycloakify-starter'];
export const themeNames: ThemeName[] = ['tps'];
Change Keycloak version targets
// src/kc.gen.tsx
plugins: [
react(),
keycloakify({
themeName: 'tps',
accountThemeImplementation: 'Multi-Page',
keycloakVersionTargets: { '21-and-below': false, '23': false, '24': false, '25': false, '26-and-above': true }
})
Build
# build
bun build-keycloak-theme # or
bun run build-keycloak-theme # create .jar file in dist.
# copy `keycloak-theme-for-kc-26-and-above.jar` file to keycloak server
scp \\wsl.localhost\...\keycloakify-starter\dist_keycloak\keycloak-theme-for-kc-26-and-above.jar {remote-server}:{path}/keycloak/themes
Deploy in keycloak container: mount theme to /opt/keycloak/providers/
...
volumes:
- ./themes:/opt/keycloak/providers/
...
References: