Vite
🚨 WARNING: ADVANCED USERS ONLY 🚨
If you're unsure what this section is about, this approach is NOT for you. Instead, follow the Quick Start Guide and fork the starter project.
This section is only for developers who already have an existing project and need to integrate a Keycloak theme within it to reuse existing components and styles.
🔹 If you're just trying to get started with Keycloakify, stop here—the starter projects provide a much simpler and recommended path.
🔹 If you proceed without fully understanding how this approach differs from the starter project, you will likely get confused about what you’re actually doing, attempt to simplify things, and end up hitting a roadblock.
If you have a Vite project you can integrate Keycloakify directly inside it.
Svelte: Although this guide uses React as an example it's also applicable for Svelte, you just need to adapt it when relevent.
Let's assume we're working with a freshly initialized Vite project.


Let's start by installing Keycloakify (and optionally Storybook) to our project:
yarn add keycloakify
# Installing storybook is optional
yarn add --dev storybook @storybook/react @storybook/react-vite
Next we want to move the relevant files from the starter template into our project:
cd my-react-app
git clone https://github.com/keycloakify/keycloakify-starter tmp
mv tmp/src src/keycloak-theme
# Note for the following command: If you already have Storybook setup
# in your project you can skip this.
# Only make sure you have `staticDirs: ["../public"]` in your .storybook/main.ts
mv tmp/.storybook .
rm -rf tmp
rm src/keycloak-theme/vite-env.d.ts
mv src/keycloak-theme/main.tsx src/main.tsx

Now you want to modify your entry point so that:
If the kcContext global is defined, render your Keycloakify theme
Else, reder your App as usual.
Let's say, for example, your src/main.tsx file currently looks like this:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./index.css";
import { MyProvider } from "./MyProvider";
createRoot(document.getElementById('root')!).render(
<StrictMode>
<MyProvider>
<App />
</MyProvider>
</StrictMode>,
);
You want to rename this file to src/main.app.tsx (for example) and modify it as follows:
import App from "./App.tsx";
import "./index.css";
import { MyProvider } from "./MyProvider.tsx";
export default function AppEntrypoint() {
return (
<MyProvider>
<App />
</MyProvider>
)
}
Then you want to create the following src/main.tsx file, you can copy and paste the following code (it does not need to be adapted):
import { createRoot } from "react-dom/client";
import { StrictMode, lazy, Suspense } from "react";
import { KcPage, type KcContext } from "./keycloak-theme/kc.gen";
const AppEntrypoint = lazy(() => import("./main.app"));
// The following block can be uncommented to test a specific page with `yarn dev`
// Don't forget to comment back or your bundle size will increase
/*
import { getKcContextMock } from "./keycloak-theme/login/KcPageStory";
if (import.meta.env.DEV) {
window.kcContext = getKcContextMock({
pageId: "register.ftl",
overrides: {}
});
}
*/
createRoot(document.getElementById("root")!).render(
<StrictMode>
{window.kcContext ? (
<KcPage kcContext={window.kcContext} />
) : (
<Suspense>
<AppEntrypoint />
</Suspense>
)}
</StrictMode>
);
declare global {
interface Window {
kcContext?: KcContext;
}
}
You also need to use Keycloakify's Vite plugin. Here we don't provide any build options but you probably at least want to define keycloakVersionTargets.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { keycloakify } from "keycloakify/vite-plugin";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
keycloakify({
accountThemeImplementation: "none"
})
],
})
Finally you want to add to your package.json
a script for building the theme and another one to start storybook.
{
"name": "my-react-app",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"build-keycloak-theme": "npm run build && keycloakify build",
"storybook": "storybook dev -p 6006"
},
// ...
Last setp is to exclude from your html <head />
things that aren't relevent in the context of Keycloak pages.
Do not blindly copy/paste, this is just an example!
You have to figure out what does and does not make sense to be in the <head/>
of your Keycloak UI pages.
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="keycloakify-ignore-start">
<title>ACME Dashboard</title>
<script>
window.ENV = {
API_ADDRESS: '${API_ADDRESS}',
SENTRY_DSN: '${SENTRY_DSN}'
};
</script>
<meta name="keycloakify-ignore-end">
<!-- ... -->
</head>
<!-- ... -->
In the above example we tell Keycloakify not to include the <title>
because Keycloakify will set it dynamically to something like "ACME- Login" or "ACME - Register".
We also exclude a placeholder script for injecting environnement variables at container startup.
That's it, your project is ready to go! 🎉
You can run npm run build-keycloak-theme
, the JAR distribution of your Keycloak theme will be generated in dist\_keycloak
.
You're now able to use all the Keycloakify commands (npx keycloakify --help
) from the root of your project.
If you're currently using keycloak-js or react-oidc-context to manage user authentication in your app you might want to checkout oidc-spa, the alternative from the Keycloakify team.
If you have any issues reach out on Discord! We're here to help!
Last updated
Was this helpful?