# CSS Customization
{% hint style="info" %}
This page is a must-read. Even if you plan to redesign the pages at the component level, you should at least understand how to remove the default CSS styles.
{% endhint %}
## 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 example `kcLabelClass`.
* One or more classes starting with `pf-`, for example `pf-c-form__label`, `pf-c-form__label-text`.
Inspecting an input label on the login page.png?alt=media)
import "./main.css";
// ...
{% endtab %}
{% tab title="Svelte" %}
<script lang="ts">
import "./main.css";
import Template from '@keycloakify/svelte/login/Template.svelte';
...
{% endtab %}
{% tab title="Angular" %}
import "./main.css";
import { getDefaultPageComponent, type KcPage } from '@keycloakify/angular/login';
// ...
{% endtab %}
{% endtabs %}
This is the result:
.png?alt=media)
A red border has been applied to every input label
import "bootstrap/dist/css/bootstrap.min.css";
import { Suspense, lazy } from "react";
import type { ClassKey } from "keycloakify/login";
import type { KcContext } from "./KcContext";
import { useI18n } from "./i18n";
import DefaultPage from "keycloakify/login/DefaultPage";
import Template from "keycloakify/login/Template";
const UserProfileFormFields = lazy(
() => import("keycloakify/login/UserProfileFormFields")
);
const doMakeUserConfirmPassword = true;
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
const { i18n } = useI18n({ kcContext });
return (
<Suspense>
{(() => {
switch (kcContext.pageId) {
default:
return (
<DefaultPage
kcContext={kcContext}
i18n={i18n}
classes={classes}
Template={Template}
doUseDefaultCss={true}
UserProfileFormFields={UserProfileFormFields}
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
/>
);
}
})()}
</Suspense>
);
}
const classes = {
kcLabelClass: "form-label col-form-label",
} satisfies { [key in ClassKey]?: string };
By doing this, you replace the Patternfly classes `pf-c-form__label pf-c-form__label-text` with the Bootstrap classes `form-label col-form-label`.
In practice, if you inspect the element in your browser, the form label that was previously rendered as:
```html
.png?alt=media)
The default look of the "Sign In" button
.png?alt=media)
How the "Sign In" button looks when all Patternfly styles are removed
.png?alt=media)
Inspecting the CSS classes applied to the "Sign In" button
// ...
const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };
{% endtab %}
{% tab title="Angular" %}
const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };
{% endtab %}
{% tab title="Svelte" %}
<script lang="ts">
// ...
const classes = {
kcButtonClass: "",
kcButtonPrimaryClass: "",
kcButtonBlockClass: "",
kcButtonLargeClass: ""
} satisfies { [key in ClassKey]?: string };
{% endtab %}
{% endtabs %}
After saving these changes, here’s the result:
.png?alt=media)
All Patternfly classes have been stripped out, restoring the button to its default HTML style.

Button with custom style
.png?alt=media)
The login page completely unstyled (doUseDefaultCss set to false).
// ...
<DefaultPage
kcContext={kcContext}
i18n={i18n}
classes={classes}
Template={Template}
doUseDefaultCss={false}
UserProfileFormFields={UserProfileFormFields}
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
/>
{% endtab %}
{% tab title="Svelte" %}
{#await page() then { default: Page }}
<Page
{kcContext}
i18n={i18n}
{classes}
{Template}
{UserProfileFormFields}
doUseDefaultCss={false}
{doMakeUserConfirmPassword}
></Page>
{/await}
{% endtab %}
{% tab title="Angular" %}
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,
};
}
}
{% endtab %}
{% endtabs %}
### Disabling the default styles only on some pages
A common scenario is using [`npx keycloakify eject-page`](https://docs.keycloakify.dev/common-use-case-examples/using-a-component-library) 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:
{% tabs %}
{% tab title="React" %}
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}
/>
);
}
{% endtab %}
{% tab title="Angular" %}
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,
};
}
{% endtab %}
{% tab title="Svelte" %}
<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}
{% endtab %}
{% endtabs %}
### Removing the classes in ejected components (kcClsx)
If you have ejected some pages with [`npx keycloakify eject-page`](https://docs.keycloakify.dev/common-use-case-examples/using-a-component-library) 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.