description |
---|
Customizing the Single Page Account UI |
The present documation page is a transcript of what I explain in this video:
{% embed url="https://youtu.be/PCNd3Nso1mY" %} This excerpt is from a video call with the Keycloak team, where we introduced the support for Account SPA customization. {% endembed %}
The account Single Page Account theme before customization
You've made your mind and opted for the Single Page Account UI?
Great, let's start by initializing you theme:
npx keycloakify initialize-account-theme
When prompted, select the "Single-Page" option
This command will create the nessesary boilerpate and add to your project dependencies the required dependencies of the latest Account UI.
Dependency added to your project when using initializing the Single-Page Account UI
Before starting the customization, let's make sure that everything works by adding a simple console.log.
import { lazy } from "react";
import { KcAccountUiLoader } from "@keycloakify/keycloak-account-ui";
import type { KcContext } from "./KcContext";
const KcAccountUi = lazy(() => import("@keycloakify/keycloak-account-ui/KcAccountUi"));
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
console.log("This is my account theme!");
return <KcAccountUiLoader kcContext={kcContext} KcAccountUi={KcAccountUi} />;
}
Then let's start Keycloak and test it live:
npx keycloakify start-keycloak
Selet Keycloak 25.
Keycloak 25 up and runing on your computer
Once you get the confirmation message that Keycloak is up and running you can reach the https://my-theme.keycloakify.dev to get redirected to your Login theme.
Use the test credentials to authenticate as the test user:
Authenticating as the test user
On the next page you'll be provided with a link to the Account pages:
Authenticated as "testuser" on the my-theme.keycloakify.dev utility app
You should be able to see your log statement confirming that you are indeed running your theme.
Compilation of your theme is running in watch mode when using the start-keycloak command, you can eddit your console.log message, save and after a few seconds reload the page, you should see the message updated.
After completing the initialization process, it's a good time to commit the changes.
git add -A
git commit -am "Initialize the Single-Page Account Theme"
To customize the text and the translations it's done by creating .properties files in src/account/messages.\
{% hint style="info" %} You can find the base i18n resources in:
node_modules/@keycloakify/keycloak-account-ui/messages
Don't edit theses files directly though, keep reading! {% endhint %}
Let's say we want to change some text in the UI.
Create the following file:
{% code title="src/account/messages/messages_en.properties" %}
personalInfo=Personal info cool
{% endcode %}
Result:
We just changed the text only in english. You need to do the same for all the languages that you wish to support.
{% hint style="success" %}
You can also change the texts in the Keycloak Account UI in the Localization tab.
Learn more: See this.
{% endhint %}
We just see how to add or modify texts for languages that are supported by default.
If, however, you want to add support for an extra language, you can do it by creating a new propery file.
Example, adding support for the Vietnamese:
You can now go in the Keycloak Admin Console and select Vn in the list of supported language:
Note: Keycloak does not provide a way to provide the corect label at the moment
Result after selecting Vn in the Account UI:
You can customize some aspect of the account theme witout having to go down at the React component level.
If you stick to this level of customization the Keycloak team is able to guarenty that you'll be able to keep your theme compatible with upcoming version of Keycloak with minimal maintenance effort.
Let's see what we can do.
First start by adding a logo file in your src directory somewhere, example:
And pass a reference to it as props of the <KcAccountUiLoader />
component:
import { lazy } from "react";
import { KcAccountUiLoader } from "@keycloakify/keycloak-account-ui";
import type { KcContext } from "./KcContext";
import myLogoPngUrl from "./assets/my-logo.png";
const KcAccountUi = lazy(() => import("@keycloakify/keycloak-account-ui/KcAccountUi"));
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
return (
<KcAccountUiLoader
kcContext={kcContext}
KcAccountUi={KcAccountUi}
logoUrl={myLogoPngUrl}
/>
);
}
After saving and reloading you should be able to see that the logo has been updated:
The Keycloak logo has been replaced by the Keycloakify logo
Beside changing option in your Keycloak realm configuration you can define what options should be displayed and when in the left pannel.
For that you can use the content props of the KcAccountUiLoader
component.
You can start by copy/pasting the default content located in node_modules/@keycloakify/keycloak-account-ui/src/public/content.ts
import { lazy } from "react";
import { KcAccountUiLoader } from "@keycloakify/keycloak-account-ui";
import type { KcContext } from "./KcContext";
import myLogoPngUrl from "./assets/my-logo.png";
const KcAccountUi = lazy(() => import("@keycloakify/keycloak-account-ui/KcAccountUi"));
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
return (
<KcAccountUiLoader
kcContext={kcContext}
KcAccountUi={KcAccountUi}
logoUrl={myLogoPngUrl}
content={[
{
label: "personalInfo",
path: ""
},
{
label: "accountSecurity",
children: [
{
label: "signingIn",
path: "account-security/signing-in"
},
{
label: "deviceActivity",
path: "account-security/device-activity"
},
{
label: "linkedAccounts",
path: "account-security/linked-accounts",
isVisible: "isLinkedAccountsEnabled"
}
]
},
{
label: "applications",
path: "applications"
},
{
label: "groups",
path: "groups",
isVisible: "isViewGroupsEnabled"
},
{
label: "resources",
path: "resources",
isVisible: "isMyResourcesEnabled"
},
{
label: "oid4vci",
path: "oid4vci",
isVisible: "isOid4VciEnabled"
}
]}
/>
);
}
Let's for example comment out the deviceActivity section.
Before
Commenting out deviceActivity
After, the Device Activity section has disapeared
The official way of customizing the look of the Account UI is to overload the PaternFly CSS variables:
{% embed url="https://www.patternfly.org/components/button/html/#css-variables" %}
But we are aware that this isn't enough for most of you.
Beyond that you can of course import your custom CSS and use the PaternFly utility classes as target but be aware that theses classes can be changed in the future.
Example loading some custom CSS:
The red boder has been applied on all the element that have the pf-v5-c-page__main-secrion class
To customize the Account theme at the React component level you want to use the eject-page command and slect "account".
npx keycloakify eject-page
After running this command you'll be able to see that the following change has been automatically applied:
{% code title="src/account/KcPage.tsx" %}
import { lazy } from "react";
import { KcAccountUiLoader } from "@keycloakify/keycloak-account-ui";
import type { KcContext } from "./KcContext";
-const KcAccountUi = lazy(()=> import("@keycloakify/keycloak-account-ui/KcAccountUi"));
+const KcAccountUi = lazy(() => import("./KcAccountUi"));
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
return (
<KcAccountUiLoader
kcContext={kcContext}
KcAccountUi={KcAccountUi}
/>
);
}
{% endcode %}
Also the KcAccountUi component has be copied over from node_modules/@keycloakify/keycloak-account-ui/src/KcAccountUi.tsx to your codebase at src/account/KcAccountUi.tsx.
KcAccountUi.tsx has been ejected
That what you'll want to each time you'll want to take ownership of some component of the Account UI: Copy the original source file into your codebase and update the absolute imports by relative imports.
Let's see in practice how we would eject the routes:
cp node_modules/@keycloakify/keycloak-account-ui/src/routes.tsx src/account/
Then you want to update the absolututes import of the routes to your local routes in KcAccountUI.tsx
- import { routes } from "@keycloakify/keycloak-account-ui/routes";
+ import { router } from "./routes";
And that's it, you now own the routes!
Moving forward you can incrementally "eject" the components you need to take ownerhip over by followind the same process.
Be aware: The more components you eject, the more work it will represent to mainain your theme up to date with the future evolution of Keycloak.
Each time a new version of Keycloak is released, a new version of @keycloak/keycloak-account-ui is also released with the same version number.
This does not nessesarely means that in order to have a custom theme that works with Keycloak 25.0.2 for example you need to use @keycloak/[email protected]. Actually it's very likely that you theme will still work with Keycloak 26, however at some point your theme will break with future version of Keycloak and you'll have to upgrade.
Keycloakify does not use the NPM package @keycloak/keycloak-account-ui but an automatically repackaged distribution of it: @keycloakify/keycloak-account-ui.
So, when comes the time to upgrade you want to navigate to:\
{% embed url="https://github.com/keycloakify/keycloak-account-ui" %}
And look in the README in the installation section:
Instalation section of keycloakify/keycloak-account-ui version 25.0.2
You want to copy and paste the dependencies into the package.json of your Keycloakify project.
The readme is generated automatically, you can trust that is always up do date.
You migh wonder why there's only RC releases of @keycloakify/keycloak-account-ui, it's because we want to match the version number of the upstream package @keycloak/keycloak-account-ui but still be able to publish update when minor changes on the re-packaging distribution is needed.