Overview
Keycloak is a powerful open-source Identity and Access Management solution — but its default FreeMarker-based theming system is clunky and hard to maintain. This project replaces those legacy templates with a fully modern React + Tailwind CSS v4 stack using the Keycloakify v11 library, which acts as a bridge between React components and Keycloak's theming engine.
The result is a pixel-perfect, responsive login/registration flow that feels like a native part of any modern web application — and it's available as a ready-to-use npm package.
npm: @oussemasahbeni/keycloakify-login-shadcn
Key Features
- 35+ Keycloak pages — Every login flow page is a clean React component with full TypeScript safety.
- Dark / Light / System mode — Persistent theme toggle that respects the user's OS preference.
- Tailwind CSS v4 + shadcn/ui — Consistent, accessible component library for a polished look.
- Multi-language & RTL support — i18n ready with English, French, and Arabic translations.
- Custom email templates — Branded transactional emails (verification, password reset, TOTP, etc.) built with
jsx-email. - 16+ social login providers — Pre-styled icons for Google, GitHub, Microsoft, and more.
- Storybook integration — UI components are developed and previewed in isolation before being wired into Keycloak.
- Zero-config deployment — Exported as a standard
.jarfile that drops into any Keycloak instance. - Vite powered — Fast development with HMR and optimized builds.
Technical Deep Dive
Keycloakify Bridge
Keycloakify intercepts Keycloak's FreeMarker template resolution and routes page renders to React components. Each page is mapped 1-to-1:
// src/login/pages/Login.tsx
import { KcPage, KcContext } from 'keycloakify/login';
export function Login({ kcContext }: { kcContext: KcContext.Login }) {
return (
<div className="min-h-screen flex items-center justify-center bg-background">
<LoginForm realm={kcContext.realm} url={kcContext.url} />
</div>
);
}
Component Architecture
src/
├── login/
│ ├── assets/
│ │ ├── img/ # Logo and images
│ │ └── fonts/ # Custom fonts
│ ├── pages/ # One component per Keycloak page (35+)
│ ├── components/ # Shared UI (Input, Button, Logo)
│ ├── i18n.ts # Translations (EN, FR, AR)
│ └── index.css # CSS variables & Tailwind config
├── components/
│ └── ui/ # shadcn/ui components
└── email/
├── templates/ # jsx-email template components
└── locales/ # Email translation files
Build & Packaging
The project compiles to a Keycloak-compatible .jar archive via Keycloakify's build pipeline, making deployment as simple as dropping a file into Keycloak's providers/ directory.
Supported Pages
| Authentication | Account Management | Security |
|---|---|---|
| Login | Register | WebAuthn Authenticate |
| Login with Username | Update Profile | WebAuthn Register |
| Login with Password | Update Email | Configure TOTP |
| Login OTP | Delete Account | Recovery Codes |
| Login with Passkeys | Logout Confirm | Reset OTP |
| OAuth Grant | Terms & Conditions | X509 Info |
| Device Verification | Select Organization | Delete Credential |
Email Templates
Custom email templates are built with jsx-email and support multiple languages.
| Template | Description |
|---|---|
email-verification.tsx |
Email verification |
password-reset.tsx |
Password reset link |
executeActions.tsx |
Required actions |
identity-provider-link.tsx |
IDP linking |
org-invite.tsx |
Organization invitation |
event-login_error.tsx |
Login error notification |
event-update_password.tsx |
Password change notification |
event-update_totp.tsx |
TOTP configuration notification |
Quick Start (npm)
Use the published package in any Vite + React + TypeScript project:
# 1. Create a new Vite project
pnpm create vite keycloak-theme --template react-ts
cd keycloak-theme
# 2. Install dependencies
pnpm add keycloakify @oussemasahbeni/keycloakify-login-shadcn
pnpm install
# 3. Initialize Keycloakify (select "login" + "Yes" for Stories)
npx keycloakify init
# 4. Run Storybook for visual testing
pnpm storybook
# 5. Build the Keycloak theme JAR
pnpm build-keycloak-theme
Challenges & Solutions
Challenge: Stale page re-renders during Keycloak form submission
Keycloak uses traditional HTML form POST, so React state is wiped on each round-trip.
Solution: Form state is preserved via Keycloak's built-in formData context, and validation errors are mapped from the messagesPerField API back into the React components.
Challenge: Matching Keycloak's security model for CSRF
Keycloakify automatically injects the authenticationSession token into every form, ensuring CSRF protection is never bypassed despite the React re-render.
Challenge: RTL layout for Arabic
Tailwind CSS v4 handles directional utilities natively, but component-level overrides were needed for form inputs and icon positioning.
Solution: The dir attribute is set dynamically on the root element based on the active locale, and Tailwind's rtl: variant handles layout mirroring at the component level.
Results
- 📦 Published npm package — 669+ weekly downloads on npm
- ⚡ 80% faster theming iteration compared to raw FreeMarker development
- 🌍 3 languages supported out of the box (EN, FR, AR with RTL)
- 🎨 100% brand-consistent login pages across all applications in the ecosystem
- ♿ WCAG AA compliant — fully keyboard navigable with proper ARIA labels





