Skip to main content

Customizing UI / Theming

Phase Two ships a unified theme called phasetwo-ui that covers all four Keycloak theme types — login, account, admin, and email — in a single package. It is built with Keycloakify and shadcn/ui and is the default theme on Phase Two hosted instances.

Branding is applied at runtime through realm attributes, so changes take effect immediately without rebuilding or redeploying the theme JAR. The Styles panel in the admin console (under Extensions) provides a UI for most of these settings — the Admin Portal v2 theme tokens described below are not exposed there yet. To access it, ensure the phasetwo-ui theme is selected for the Admin theme in Realm Settings > Themes.

Email theme

For email branding (logo, footer), set your realm's email theme to phasetwo-ui. This unlocks the Email Branding settings described in the Emails guide.

If you are looking to build a fully custom theme, we recommend using Keycloakify. Phase Two are sponsors of the project.

Theme selection prerequisite

The Styles panel and all branding features described on this page require the phasetwo-ui theme to be active. Go to Realm Settings > Themes and set:

  • Login theme: phasetwo-ui
  • Admin theme: phasetwo-ui
  • Account theme: phasetwo-ui
  • Email theme: phasetwo-ui

Simple

The simple override of colors and logo can be accessed in the admin UI under Extensions > Styles. The available override values are organized across four tabs.

General tab

  • Logo URL: URL of your logo image. This logo appears on login and account pages. It will be constrained to 150×150px. Use an SVG or PNG with an alpha channel so it renders correctly on any background and inside the Admin Portal. To set a separate logo for emails, use the Email tab.
  • Favicon URL: URL of your browser tab favicon.
  • App Icon URL: URL of the app icon used within the Admin Portal.

The form includes a live image preview so you can confirm your URLs are resolving correctly before saving.

Keycloak Phase Two General Style Customization

Login tab

Colors control the look of the login, registration, and related authentication pages. All values are hex color codes (e.g. #3b82f6).

Light mode

  • Primary color: Used for buttons, links, and the sidebar panel. Default: #3b82f6.
  • Secondary color: Used for secondary accents. Default: #60a5fa.
  • Background color: Page background color. Default: #ffffff.

Dark mode

The theme automatically follows the user's operating system dark mode preference. You can supply separate overrides for dark mode; if omitted, the light-mode values are used as fallbacks.

  • Primary color (dark)
  • Secondary color (dark)
  • Background color (dark)

A CSS field is also available on this tab for arbitrary stylesheet overrides, loaded after the theme styles.

Keycloak Phase Two Login Style Customization

Full CSS

The CSS field in the Login tab accepts arbitrary CSS that is loaded after the theme styles. You can use it for targeted overrides without replacing the entire theme.

The phasetwo-ui login theme is built with shadcn/ui and Tailwind CSS v4. The color system uses a set of --p2-login-* CSS variables that the theme bridges to shadcn's semantic tokens. Overriding these variables in your custom CSS is the lightest-weight way to change colors without touching the color picker fields:

:root {
--p2-login-primary-color: #5b9fdd;
--p2-login-secondary-color: #edf5fb;
--p2-login-background-color: #ffffff;
/* Text color rendered on top of the primary color (e.g. button labels) */
--p2-login-primary-foreground-color: #ffffff;
}

/* Optional: separate dark mode overrides */
.dark {
--p2-login-primary-color-dark: #3b82f6;
--p2-login-secondary-color-dark: #1e3a5f;
--p2-login-background-color-dark: #0f0f0f;
}

Phase Two has assembled a few complete custom themes. View them in our Keycloak Themes Repository.

Manually by Realm attributes

All values set through the Styles panel are stored as Realm attributes. You can set them programmatically via the Keycloak Admin REST API or in a realm export JSON. Use the following attribute keys:

General

AttributeDescription
_providerConfig.assets.logo.urlLogo URL for login and account pages
_providerConfig.assets.favicon.urlBrowser tab favicon URL
_providerConfig.assets.appicon.urlApp icon URL for the Admin Portal

Login (light mode)

AttributeDefaultDescription
_providerConfig.assets.login.primaryColor#3b82f6Buttons, links, sidebar
_providerConfig.assets.login.secondaryColor#60a5faSecondary accents
_providerConfig.assets.login.backgroundColor#ffffffPage background
_providerConfig.assets.login.primaryForegroundColor#ffffffText on the primary color. Only takes effect through the brand-token path above, as the legacy fallback for theme.v2.primaryForeground — the legacy stylesheet never emitted a variable for it.
_providerConfig.assets.login.cssArbitrary CSS appended after theme styles

Login (dark mode overrides)

Omit one and the fallback depends on the kind of color. primaryColor and secondaryColor are brand colors and fall back to their light-mode values, so a custom brand color stays consistent across modes. backgroundColor does not — it falls back to the dark default, because carrying a light background into dark mode would stop dark mode being dark.

AttributeDescription
_providerConfig.assets.login.primaryColor-darkPrimary color in dark mode
_providerConfig.assets.login.secondaryColor-darkSecondary color in dark mode
_providerConfig.assets.login.backgroundColor-darkBackground color in dark mode
_providerConfig.assets.login.primaryForegroundColor-darkForeground text in dark mode

Email branding

See the Emails page for details on email template customization.

AttributeDescription
_providerConfig.assets.logo.base64Email logo as a base64 data URI (max 1MB, PNG or SVG recommended)
_providerConfig.assets.email.footer.line1First footer line (defaults to realm display name)
_providerConfig.assets.email.footer.line2Second footer line (optional tagline or contact info)

Email

  • _providerConfig.assets.logo.base64 — base64-encoded data URI of your email logo (e.g. data:image/png;base64,...). Embedded directly in email bodies; requires the phasetwo-ui email theme.
  • _providerConfig.assets.email.footer.line1 — first footer line; defaults to realm display name when absent
  • _providerConfig.assets.email.footer.line2 — optional second footer line

Brand tokens (login, Admin Portal, and email)

The login theme and the Admin Portal are built on shadcn/ui components that read their colors from CSS variables, and the email templates use the same values inline. All three resolve one shared set of brand tokens, so branding a realm once brands every surface.

Each token is a realm attribute prefixed with _providerConfig.assets.theme.v2. — for example _providerConfig.assets.theme.v2.primary. Every color token takes an optional dark-mode override named dark<Token>, such as _providerConfig.assets.theme.v2.darkBackground.

Color tokens accept a #rgb or #rrggbb hex value — the recommended format — and also bare CSS color keywords such as red, and the rgb(), hsl(), hwb(), lab(), lch(), oklab() and oklch() functions. Contrast is only measured from hex, so if you use a keyword or a color function, set the matching foreground token explicitly rather than relying on auto-contrast. radius accepts a CSS length such as 0, 4px or 0.5rem. A value matching none of these is ignored as if unset.

Base tokens — each has a built-in default:

TokenLight defaultDark defaultDescription
background#ffffff#09090bPage surface
foreground#09090b#fafafaBody text
primary#3b82f6#3b82f6Brand color: primary buttons, links, active items
primaryForeground#ffffff#ffffffText and icons on primary; auto-contrasts when unset
secondary#60a5fa#1e3a5fSecondary buttons and accents
secondaryForeground#0a0a0a#fafafaText on secondary; auto-contrasts when unset
muted#f4f4f5#27272aRecessed surfaces: sidebar, hover states
mutedForeground#71717a#a1a1aaDe-emphasized text, such as helper text
border#e4e4e7#3f3f46Borders

Derived tokens — no default of their own; set one to override it, or leave it unset and it follows its base token. This is what lets a lone custom primary also move the focus ring:

TokenFollows when unset
cardbackground
cardForegroundforeground
accentmuted
accentForegroundforeground
inputborder
ringprimary

Other tokensradius (a CSS length) and fontFamily (a CSS font stack).

Three behaviors are worth knowing:

  • Brand color is mode-independent. Set primary or secondary and leave the dark override unset, and dark mode inherits your light value rather than reverting to the default. Surface and neutral tokens never inherit, so a light background will not light up dark mode.
  • Foregrounds auto-contrast. primaryForeground and secondaryForeground, when unset, are computed as a readable near-black or white from their background's relative luminance. foreground does the same from background, but only when that value is measurable hex.
  • Per-surface defaults differ slightly. The Admin Portal's own primary default is #1570c2 and its radius default is 0.5rem, against 0.625rem on the login pages. Those only apply when you leave the token unset.

Each token resolves independently: the theme.v2 attribute if set, otherwise the surface's legacy fallback where one exists, otherwise a derivation, otherwise the built-in default.

Email is the one surface that does not fall back to resolved defaults — only tokens you have explicitly set reach the email templates, because their built-in defaults deliberately differ from the login palette. An unbranded realm's email is unchanged.

See Admin Portal configuration for how the portal applies these at runtime, including how the sidebar derives from them.

Legacy (deprecated)

These Admin Portal keys follow the Tailwind color scale, with the lowest number lightest. They are still read, but only primaryColor700 still affects rendering, as the legacy fallback for primary. secondaryColor900 used to feed a separate cta token for the neutral emphasized button; that token has folded into primary, so a realm which only customized secondaryColor900 should set _providerConfig.assets.theme.v2.primary instead. Set the theme.v2 tokens to customize anything else.

AttributeDefaultDescription
_providerConfig.assets.portal.primaryColor100Read, but no longer affects rendering
_providerConfig.assets.portal.primaryColor200Read, but no longer affects rendering
_providerConfig.assets.portal.primaryColor400Read, but no longer affects rendering
_providerConfig.assets.portal.primaryColor500Read, but no longer affects rendering
_providerConfig.assets.portal.primaryColor600Read, but no longer affects rendering
_providerConfig.assets.portal.primaryColor700Fallback for the primary token when v2.primary is unset
_providerConfig.assets.portal.primaryColor900Read, but no longer affects rendering
_providerConfig.assets.portal.secondaryColor800Read, but no longer affects rendering; the CTA hover shade now derives from cta
_providerConfig.assets.portal.secondaryColor900Fallback for the cta token when v2.cta is unset

Custom CSS

AttributeDefaultDescription
_providerConfig.assets.portal.cssArbitrary CSS for the Admin Portal

Custom CSS is appended last, after the generated variables, so it overrides both the tokens and the built-in defaults. Target the CSS variables (--primary, --background, --radius, and the .dark block) or standard selectors.

Breaking change

Custom CSS that targeted the old generated utility classes — .bg-primary-700, .text-primary-500, .bg-primary-gradient, and friends — no longer has any effect, because the portal's components now use semantic shadcn/ui classes such as bg-primary and text-muted-foreground. Migrate that CSS to the variables above. Realms that customized primaryColor100 or primaryColor900 will see neutral surfaces after upgrading — their brand color is preserved through primaryColor700 and their CTA button color through secondaryColor900 — so set the matching v2 tokens to restore custom surfaces.

Full customization details can be viewed in the Phase Two Admin Portal Repo.

Custom Themes

If you decide to use a custom theme, you can upload it yourself from the Phase Two Dashboard under Cluster > Config > Resources. See Cluster Resources for the full walkthrough. Custom themes are available to subscribers of dedicated clusters.

Keycloakify

Keycloakify offers two methods for building custom themes:

  1. CSS Customization: Basic, but ok for simple changes. Learn more in the Keycloakify documentation.
  2. Custom (React/Angular) Components: Full customization using React or Angular components, allowing for a more robust and custom theme. If you have a theme library or set of components, you would take this route. Learn more in the Keycloakify documentation.

Ultimately what you choose depends on your needs. We have found that CSS customization of Patternfly is very difficult to get right and cover all cases. In many situations, the built in Patternfly components leave much to be desired from a UX perspective. Our friends at Keycloakify are working on a solution to this, but until that's ready we've started out providing a Shadcn starter component theme which can be used.

Shadcn Starter Theme

Shadcn is a component library that provides a set of varied and robust components that can be used to build a custom theme. It leverages Tailwind CSS for styling and Radix UI for components. The starter only handles a couple of pages, but gives a template to start from. Feel free to use it and PR additions to the templates, we would love to see them!