Skip to content
  • Design
  • Customize with code

Apply custom styling per application

You can apply unique HTML and CSS styling to each Kinde application within the same business account. Although you can only connect one Git repository for your custom pages, you can use conditional rendering to serve different designs based on which application is being accessed.

This guide will walk you through how to use the application’s Client ID to render unique styles and layouts. This doc is based on the tests and implementation we ran and provides example code, folder layout, and implemention checklist.

The clientID is a unique identifier assigned to each application in Kinde. This value distinguishes one app from another, allowing your template code to detect which application is active and render the appropriate HTML and CSS for each app accordingly.

Solution: Conditional rendering

Link to this section

The key to this solution is the clientId, a unique identifier assigned to every application you create in Kinde. This ID is passed in the request object to your custom pages. By checking the value of the clientId, your code can determine which application is active and render the corresponding HTML and CSS.

This process happens server-side, so there’s no performance loss for your users.

Before you begin

Link to this section
  • Set up a custom domain for your Kinde business.
  • Connect a Git repository to manage your custom pages.
  • Make sure your custom design files are already working. Follow this guide for more details.

Step 1: Set up file structure

Link to this section

Your repository needs to follow a specific structure for Kinde to recognize the files. For this example, we are using the simplest structure with the (default) folder to act as a fallback and a page.tsx file within it. This file will contain your conditional logic.

myApp/
├── kindeSrc/
│ └── environment/
│ └── pages/
│ └── (kinde)/
│ └── (default)/
│ └── page.tsx
│ └── layout.tsx
├── package.json
└── kinde.json

For this specific example, we focus on the default design, but you can use this for your sign up and sign pages as well.

Step 2: Find the Client ID

Link to this section

In your page.tsx file, you can access the clientId from the request object that is passed to your page component.

const DefaultPage: React.FC<KindePageEvent> = async ({ context, request }) => {
let clientId = request.authUrlParams?.clientId || null;
// ... rest of your code
};`

Step 3: Implement the conditional logic

Link to this section

Now you can use the clientId variable to build your conditional logic. For example, you can use an if/else statement, a switch statement, or a ternary operator to render different JSX for each application.

The following example shows how to render different content for three separate applications (Next.js, Python, and Nuxt.js), with a default fallback.

kindeSrc/environment/pages/(kinde)/(default)/page.tsx

Link to this section
'use server';
import {
getKindeWidget,
fetch,
type KindePageEvent,
} from '@kinde/infrastructure';
import React from 'react';
import { renderToString } from 'react-dom/server.browser';
import Layout from '../../layout';
const DefaultPage: React.FC<KindePageEvent> = async ({ context, request }) => {
// 1. Access the client ID from the request object
let clientId = request.authUrlParams?.clientId || null;
// Environment variables
const BUILDER_API_KEY = process.env.BUILDER_API_KEY;
const CLIENT_ID_NEXT_APP = process.env.CLIENT_ID_NEXT_APP;
const CLIENT_ID_PYTHON_APP = process.env.CLIENT_ID_PYTHON_APP;
// Example: Fetching dynamic content (optional)
const res = await fetch(
`https://cdn.builder.io/api/v3/content/login-page-data?apiKey=${BUILDER_API_KEY}&sort.createdDate=-1`,
{
headers: {},
method: 'GET',
}
);
const {
loginPageImage,
signInFormTextTop,
signupFormTextTop,
signInFormTextBottom,
signupFormTextBottom,
} = res?.data?.results?.[0]?.data || {};
const isUserOnLoginOrRegisterPage = request?.route?.flow;
return (
<Layout
context={context}
request={request}
props={res?.data?.results?.[0]?.data}
>
{/* 2. Use conditional rendering based on the client ID */}
{clientId == CLIENT_ID_NEXT_APP ? (
<div className='container'>
{/* Content for the Next.js App */}
<h1>Styling for the First App - Next.js</h1>
<h2>Client ID: {clientId}</h2>
<div className='login-form-wrapper'>
{getKindeWidget()}
</div>
</div>
) : clientId == CLIENT_ID_PYTHON_APP? (
<div className='container-2'>
{/* Content for the Python App */}
<h1>Styling for the Second App - Python</h1>
<h2>Client ID: {clientId}</h2>
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
</table>
<div className='login-form-wrapper'>
{getKindeWidget()}
</div>
</div>
) : (
<div className='container-default'>
{/* Fallback content for any other app (e.g., Nuxt app) */}
<h1>Default Kinde Authentication Page</h1>
<h2>Client ID: {clientId || 'Not available'}</h2>
<div className='login-form-wrapper'>
{getKindeWidget()}
</div>
</div>
)}
</Layout>
);
};
// Page Component
export default async function Page(event: KindePageEvent): Promise<string> {
const page = await DefaultPage(event);
return renderToString(page);
}

The custom CSS for classes like .container and .container-2 would typically be defined in your layout.tsx file or in a separate CSS file.

Expected output for custom designs per application

Link to this section

When a user authenticates through each of your applications, they will see a different page design based on your conditional logic. The examples below are not over-designed, but you could make them as distinct as you want.

  • Next.js App (clientId: ca3c184xxxxxxd842777bc***xxxx)

    • The user will see the content inside the first block, with the heading “Styling for the First App - Next.js”. An image of how the page for the Next.js app looks after the conditional rendering is applied
  • Python App (clientId: c41376xxxxxx244b3122dd***xxxx)

    • The user will see the second block, with the heading “Styling for the Second App - Python” and a custom HTML table. An image of how the page for the Python app looks after the conditional rendering is applied
  • Nuxt.js App or any other app (clientId: 730c34be0xxxxxxe206ec07***xxxx)

    • Since this ID doesn’t match the first two conditions, the user will see the final fallback block with the heading “Default Kinde Authentication Page”. An image of how the page for any other app (default) would look after the conditional rendering is applied