CSS Customization
Understanding the CSS class system
When you inspect the DOM in Storybook, you’ll notice most elements have at least a couple of classes applied to them:
A class starting with
kc, for examplekcLabelClass.One or more classes starting with
pf-, for examplepf-c-form__label,pf-c-form__label-text.

Classes beginning with kc don’t have any styles applied to them by default. Their sole purpose is to serve as selectors for your custom styles.
Classes beginning with pf- are Patternfly classes. Patternfly is a CSS framework created by RedHat, similar to Bootstrap, that the Keycloak team uses to build all of its UIs.
What you’ll want to do is partially or completely remove the Patternfly styles and then apply your custom ones.
Applying your custom CSS
Do not edit any file in the public/keycloakify-dev-resources directory. These files are used by Storybook to simulate a Keycloak environment during development, and they aren't part of your actual theme.
To apply your custom CSS style, use the kc classes to target the components.
.kcLabelClass {
border: 3px solid red;
}import "./main.css";
// ...<script lang="ts">
import "./main.css";
import Template from '@keycloakify/svelte/login/Template.svelte';
...import "./main.css";
import { getDefaultPageComponent, type KcPage } from '@keycloakify/angular/login';
// ...This is the result:

Removing Some of the Default Styles
Let’s consider the Sign In button on the login page:

Here’s how we can “unstyle” it so that we can apply custom styles without worrying about conflicts from the default Patternfly styles:

To remove the Patternfly styles, inspect the button in your browser:

We can see which Patternfly classes are applied by default to the standardized element:
kcButtonClass->pf-c-buttonkcButtonPrimaryClass->pf-m-primaryandlong-pf-btnkcButtonBlockClass->pf-m-blockkcButtonLargeClass->btn-lg
Since we want to remove all the default styles, we can tell Keycloakify to remove all classes assigned by default to these kc classes:
// ...
const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };<script lang="ts">
// ...
const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };After saving these changes, here’s the result:

Now you can freely apply your own custom button styles without Patternfly interfering.

Remove All the Default Styles
You may prefer to remove all Patternfly styles altogether and start fresh.

A benefit of this approach is that not only are all pf- classes stripped out in one go, but the global Patternfly stylesheet isn’t even loaded.
// ...
<DefaultPage
kcContext={kcContext}
i18n={i18n}
classes={classes}
Template={Template}
doUseDefaultCss={false}
UserProfileFormFields={UserProfileFormFields}
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
/>{#await page() then { default: Page }}
<Page
{kcContext}
i18n={i18n}
{classes}
{Template}
{UserProfileFormFields}
doUseDefaultCss={false}
{doMakeUserConfirmPassword}
></Page>
{/await}const classes = {} satisfies { [key in ClassKey]?: string };
const doUseDefaultCss = false;
const doMakeUserConfirmPassword = true;
export async function getKcPage(pageId: KcContext['pageId']): Promise<KcPage> {
switch (pageId) {
default:
return {
PageComponent: await getDefaultPageComponent(pageId),
TemplateComponent,
UserProfileFormFieldsComponent,
doMakeUserConfirmPassword,
doUseDefaultCss,
classes,
};
}
}Disabling the default styles only on some pages
A common scenario is using npx keycloakify eject-page to customize only certain pages of the login UI in depth.
For pages you've ejected, you’ll likely want to disable all default styles; however, you might prefer to keep the Patternfly styles on the pages you haven't redesigned.
Below is an example where login.ftl has been ejected and its default styles are disabled, while the other pages remain styled:
switch (kcContext.pageId) {
case "login.ftl":
return (
<Login
{...{ kcContext, i18n, classes }}
Template={Template}
doUseDefaultCss={false}
/>
);
default:
return (
<DefaultPage
kcContext={kcContext}
i18n={i18n}
classes={classes}
Template={Template}
doUseDefaultCss={true}
UserProfileFormFields={UserProfileFormFields}
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
/>
);
} switch (pageId) {
case 'login.ftl':
return {
PageComponent: (await import('./pages/login/login.component')).LoginComponent,
TemplateComponent,
UserProfileFormFieldsComponent,
doMakeUserConfirmPassword,
doUseDefaultCss: false,
classes,
};
default:
return {
PageComponent: await getDefaultPageComponent(pageId),
TemplateComponent,
UserProfileFormFieldsComponent,
doMakeUserConfirmPassword,
doUseDefaultCss: true,
classes,
};
}<script lang="ts">
// ...
const doUseDefaultCss = (()=>{
switch(kcContext.pageId){
case "login.ftl": return false;
default: return true;
}
})();
const page = async (): Promise<{ default?: Component<any> }> => {
switch (kcContext.pageId) {
case 'login.ftl':
return import('./pages/Login.svelte"');
default:
return import('@keycloakify/svelte/login/DefaultPage.svelte');
}
};
</script>
{#await page() then { default: Page }}
<Page
{kcContext}
i18n={i18n}
{classes}
{Template}
{UserProfileFormFields}
{doUseDefaultCss}
{doMakeUserConfirmPassword}
></Page>
{/await}Removing the classes in ejected components (kcClsx)
If you have ejected some pages with npx keycloakify eject-page and disabled the default styles by setting doUseDefaultCss to false, you might wonder if you need to keep the kcClsx in the pages. For example:
<input
tabIndex={7}
disabled={isLoginButtonDisabled}
className={kcClsx(
"kcButtonClass",
"kcButtonPrimaryClass",
"kcButtonBlockClass",
"kcButtonLargeClass"
)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
/>The short answer is no; feel free to remove them.
Just be aware that if you have defined any custom CSS targeting those classes (for example .kcButtonClass { /* ... */ }), they will no longer apply once you remove the classes.
Last updated
Was this helpful?