Appearance prop
The appearance prop can be applied to React's <ClerkProvider>
to share styles across every component, or individually to any of the Clerk components.
This applies to all of the React-based packages, like Next.js and Gatsby, as well as the pure JavaScript ClerkJS package.
Using a pre-built theme
Clerk offers a set of themes that can be used with the appearance
prop. The themes are available as a package called @clerk/themes
.
terminalnpm install @clerk/themes
terminalyarn add @clerk/themes
terminalpnpm add @clerk/themes
Usage
To use a theme, import it from @clerk/themes
and pass it to the appearance
prop of a Clerk component. You can pass it to the <ClerkProvider>
component to apply it to all Clerk components in your app or you can pass it to a single Clerk component.
Pass a theme to <ClerkProvider>
To apply a theme to all Clerk components, pass the appearance
prop to the <ClerkProvider>
component. The appearance
prop accepts the property baseTheme
, which can be set to a theme.
In the example below, the dark
theme is applied to all Clerk components.
/src/app/layout.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark } from '@clerk/themes'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <ClerkProvider appearance={{ baseTheme: dark }} > <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ) }
_app.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark } from '@clerk/themes'; import type { AppProps } from "next/app"; function MyApp({ Component, pageProps }: AppProps) { return ( <ClerkProvider appearance={{ baseTheme: dark }} > <Component {...pageProps}/> </ClerkProvider> ) } export default MyApp;
app.tsximport React from "react"; import "./App.css"; import { dark } from '@clerk/themes'; import { ClerkProvider } from "@clerk/clerk-react"; if (!process.env.REACT_APP_CLERK_PUBLISHABLE_KEY) { throw new Error("Missing Publishable Key") } const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY; function App() { return ( <ClerkProvider appearance={{ baseTheme: dark }} publishableKey={clerkPubKey} > <div>Hello from clerk</div> </ClerkProvider> ); } export default App;
app/root.tsx// Import ClerkApp import { ClerkApp } from "@clerk/remix"; import { dark } from '@clerk/themes'; import type { MetaFunction,LoaderFunction } from "@remix-run/node"; import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, } from "@remix-run/react"; import { rootAuthLoader } from "@clerk/remix/ssr.server"; export const meta: MetaFunction = () => ({ charset: "utf-8", title: "New Remix App", viewport: "width=device-width,initial-scale=1", }); export const loader: LoaderFunction = (args) => rootAuthLoader(args); function App() { return ( <html lang="en"> <head> <Meta /> <Links /> </head> <body> <Outlet /> <ScrollRestoration /> <Scripts /> <LiveReload /> </body> </html> ); } export default ClerkApp(App, { appearance: { baseTheme: dark, }, });
You can also stack themes by passing an array of themes to the baseTheme
property of the appearance
prop. The themes will be applied in the order they are listed. If styles overlap, the last defined theme will take precedence.
In the example below, the dark
theme is applied first, then the neobrutalism
theme is applied on top of it.
/src/app/layout.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark, neobrutalism } from '@clerk/themes'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism] }} > <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ) }
_app.tsximport { ClerkProvider, SignIn } from '@clerk/nextjs'; import { dark, neobrutalism } from '@clerk/themes'; import type { AppProps } from "next/app"; function MyApp({ Component, pageProps }: AppProps) { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism] }} > <Component {...pageProps}/> </ClerkProvider> ) } export default MyApp;
app.tsximport React from "react"; import "./App.css"; import { dark, neobrutalism } from '@clerk/themes'; import { ClerkProvider } from "@clerk/clerk-react"; if (!process.env.REACT_APP_CLERK_PUBLISHABLE_KEY) { throw new Error("Missing Publishable Key") } const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY; function App() { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism] }} publishableKey={clerkPubKey} > <div>Hello from clerk</div> </ClerkProvider> ); } export default App;
app/root.tsx// Import ClerkApp import { ClerkApp } from "@clerk/remix"; import { dark, neobrutalism } from '@clerk/themes'; import type { MetaFunction,LoaderFunction } from "@remix-run/node"; import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, } from "@remix-run/react"; import { rootAuthLoader } from "@clerk/remix/ssr.server"; export const meta: MetaFunction = () => ({ charset: "utf-8", title: "New Remix App", viewport: "width=device-width,initial-scale=1", }); export const loader: LoaderFunction = (args) => rootAuthLoader(args); function App() { return ( <html lang="en"> <head> <Meta /> <Links /> </head> <body> <Outlet /> <ScrollRestoration /> <Scripts /> <LiveReload /> </body> </html> ); } export default ClerkApp(App, { appearance: { baseTheme: [dark, neobrutalism] }, });
You can apply a theme to all instances of a Clerk component by passing the component to the appearance
prop of the <ClerkProvider>
. The appearance
prop accepts the name of the Clerk component you want to style as a key.
In the example below, the neobrutalism
theme is applied to all instances of the <SignIn />
component.
/src/app/layout.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark, neobrutalism } from '@clerk/themes'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <ClerkProvider appearance={{ baseTheme: dark, signIn: { baseTheme: neobrutalism }, }} > <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ) }
_app.tsximport { ClerkProvider, SignIn } from '@clerk/nextjs'; import { dark } from '@clerk/themes'; import type { AppProps } from "next/app"; function MyApp({ Component, pageProps }: AppProps) { return ( <ClerkProvider appearance={{ baseTheme: dark, signIn: { baseTheme: neobrutalism }, }} > <Component {...pageProps}/> </ClerkProvider> ) } export default MyApp;
app.tsximport React from "react"; import "./App.css"; import { dark } from '@clerk/themes'; import { ClerkProvider } from "@clerk/clerk-react"; if (!process.env.REACT_APP_CLERK_PUBLISHABLE_KEY) { throw new Error("Missing Publishable Key") } const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY; function App() { return ( <ClerkProvider appearance={{ baseTheme: dark, signIn: { baseTheme: neobrutalism }, }} publishableKey={clerkPubKey} > <div>Hello from clerk</div> </ClerkProvider> ); } export default App;
app/root.tsx// Import ClerkApp import { ClerkApp } from "@clerk/remix"; import { dark } from '@clerk/themes'; import type { MetaFunction,LoaderFunction } from "@remix-run/node"; import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, } from "@remix-run/react"; import { rootAuthLoader } from "@clerk/remix/ssr.server"; export const meta: MetaFunction = () => ({ charset: "utf-8", title: "New Remix App", viewport: "width=device-width,initial-scale=1", }); export const loader: LoaderFunction = (args) => rootAuthLoader(args); function App() { return ( <html lang="en"> <head> <Meta /> <Links /> </head> <body> <Outlet /> <ScrollRestoration /> <Scripts /> <LiveReload /> </body> </html> ); } export default ClerkApp(App, { appearance: { baseTheme: dark, signIn: { baseTheme: neobrutalism }, }, });
Pass a theme to a single Clerk component
To apply a theme to a single Clerk component, pass the appearance
prop to the component. The appearance
prop accepts the property baseTheme
, which can be set to a theme.
/app/sign-in/[[...sign-in]]/page.tsximport { SignIn } from "@clerk/nextjs"; import { dark } from "@clerk/themes"; export default function Page() { return <SignIn appearance={{ baseTheme: dark }} path="/sign-in" />; }
/pages/sign-in/[[...index]].tsximport { SignIn } from "@clerk/nextjs"; import { dark } from "@clerk/themes"; const SignInPage = () => ( <SignIn appearance={{ baseTheme: dark }} path="/sign-in" /> ); export default SignInPage;
/src/sign-in/[[...index]].tsximport { SignIn } from "@clerk/clerk-react"; import { dark } from "@clerk/themes"; const SignInPage = () => ( <SignIn appearance={{ baseTheme: dark }} path="/sign-in" signUpUrl="/sign-up" /> ); export default SignInPage;
app/routes/sign-in/$.tsximport { SignIn } from "@clerk/remix"; import { dark } from "@clerk/themes"; export default function SignInPage() { return ( <div style={{ border: "2px solid blue", padding: "2rem" }}> <h1>Sign In route</h1> <SignIn appearance={{ baseTheme: dark }} path="/sign-in" signUpUrl="/sign-up" /> </div> ); }
Customize a theme using variables
You can customize a theme by passing an object of variables to the variables
property of the appearance
prop. The variables
property is used to adjust the general styles of the component's base theme, like colors, backgrounds, typography.
In the example below, all Clerk components will have the dark
theme with the neobrutalism
theme applied on top of it, and the primary color will be set to red. All <SignIn />
components will have the shadesOfPurple
theme applied on top of the dark
and neobrutalism
themes, and the primary color will be set to blue.
For a list of all of the variables you can customize, and for more examples on how to use the variables
property, see the Variables docs.
/src/app/layout.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'; export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism], variables: { colorPrimary: 'red' }, signIn: { baseTheme: [shadesOfPurple], variables: { colorPrimary: 'blue' } } }} > <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ) }
_app.tsximport { ClerkProvider } from '@clerk/nextjs'; import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'; import type { AppProps } from "next/app"; function MyApp({ Component, pageProps }: AppProps) { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism], variables: { colorPrimary: 'red' }, signIn: { baseTheme: [shadesOfPurple], variables: { colorPrimary: 'blue' } } }} > <Component {...pageProps}/> </ClerkProvider> ) } export default MyApp;
app.tsximport React from "react"; import "./App.css"; import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'; import { ClerkProvider } from "@clerk/clerk-react"; if (!process.env.REACT_APP_CLERK_PUBLISHABLE_KEY) { throw new Error("Missing Publishable Key") } const clerkPubKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY; function App() { return ( <ClerkProvider appearance={{ baseTheme: [dark, neobrutalism], variables: { colorPrimary: 'red' }, signIn: { baseTheme: [shadesOfPurple], variables: { colorPrimary: 'blue' } } }} publishableKey={clerkPubKey} > <div>Hello from clerk</div> </ClerkProvider> ); } export default App;
app/root.tsx// Import ClerkApp import { ClerkApp } from "@clerk/remix"; import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'; import type { MetaFunction,LoaderFunction } from "@remix-run/node"; import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, } from "@remix-run/react"; import { rootAuthLoader } from "@clerk/remix/ssr.server"; export const meta: MetaFunction = () => ({ charset: "utf-8", title: "New Remix App", viewport: "width=device-width,initial-scale=1", }); export const loader: LoaderFunction = (args) => rootAuthLoader(args); function App() { return ( <html lang="en"> <head> <Meta /> <Links /> </head> <body> <Outlet /> <ScrollRestoration /> <Scripts /> <LiveReload /> </body> </html> ); } export default ClerkApp(App, { appearance={{ baseTheme: [dark, neobrutalism], variables: { colorPrimary: 'red' }, signIn: { baseTheme: [shadesOfPurple], variables: { colorPrimary: 'blue' } } }} });
Create a custom theme
You can make a custom theme for your app's Clerk component by customizing the styles that are applied to each element.
This can be done with one of three different methods of styling:
No matter which method you choose, you'll need to know how to identify the element you want to style.
Identify the underlying element
You can identify the underlying element by inspecting the HTML of the Clerk component. You can do this by right-clicking on the component in your browser and selecting "Inspect Element" or "Inspect":
When you select an element that is part of a Clerk component, you'll notice a list of classes like so:
cl-formButtonPrimary cl-button 🔒️ cl-internal-1ta0xpz
Any of the classes listed before the lock icon (🔒️) are safe to rely on, such as cl-formButtonPrimary
or cl-button
. You'll use these classes to target the respective Clerk component elements.
Anything after the lock icon (🔒️) are internal classes used for Clerk's internal styling and should not be modified.
Use global CSS to style Clerk components
Using this knowledge about the publicly available classes, you can target the elements with global CSS.
Here's an example of how you can target the primary button in a Clerk component:
styles/global.css.cl-formButtonPrimary { font-size: 14px; text-transform: none; background-color: #611bbd; } .cl-formButtonPrimary:hover, .cl-formButtonPrimary:focus, .cl-formButtonPrimary:active { background-color: #49247a; }
Use custom CSS classes to style Clerk components
You're able to pass additional classes to Clerk component elements by using the elements
property on appearance
in your ClerkProvider
.
If you look back to the list of classes applied to a Clerk component's element, you'll see a list of classes like so:
cl-formButtonPrimary cl-button 🔒️ cl-internal-1ta0xpz
Remove the cl-
prefix and use it as the key for a new object in the elements
property. The value of this object should be the string of classes you want to apply to the element.
app.tsximport { ClerkProvider, SignIn } from "@clerk/nextjs"; import type { AppProps } from "next/app"; function MyApp({ pageProps }: AppProps) { return ( <ClerkProvider {...pageProps}> <SignIn appearance={{ elements: { formButtonPrimary: "your-org-button org-red-button", }, }} path="/sign-in" /> </ClerkProvider> ); } export default MyApp;
Use Tailwind classes to style Clerk components
By using the method outlined above, you can use Tailwind classes to style Clerk components.
app.tsximport { ClerkProvider, SignIn } from "@clerk/nextjs"; import type { AppProps } from "next/app"; function MyApp({ pageProps }: AppProps) { return ( <ClerkProvider {...pageProps}> <SignIn appearance={{ elements: { formButtonPrimary: "bg-slate-500 hover:bg-slate-400 text-sm normal-case", }, }} path="/sign-in" /> </ClerkProvider> ); } export default MyApp;
Using CSS Modules
CSS modules are a great way to scope your CSS to a specific component. Clerk components can be styled with CSS modules by using the same method as outlined above.
Simply create your Module file and add the CSS you want to apply.
styles/SignIn.module.css.primaryColor { background-color: bisque; color: black; }
Then you can apply this by importing the file and using the classes whenever required:
app.tsximport styles from "../styles/SignIn.module.css"; import { ClerkProvider, SignIn } from "@clerk/nextjs"; import type { AppProps } from "next/app"; function MyApp({ pageProps }: AppProps) { return ( <ClerkProvider {...pageProps}> <SignIn appearance={{ elements: { formButtonPrimary: styles.primaryColor, }, }} path="/sign-in" /> </ClerkProvider> ); } export default MyApp;
Use inline CSS objects to style Clerk components
Using the same method for identifying elements as mentioned previously, you can pass an object of CSS properties to the elements
property on appearance
in your ClerkProvider
.
app.tsximport { ClerkProvider, SignIn } from "@clerk/nextjs"; import type { AppProps } from "next/app"; function MyApp({ pageProps }: AppProps) { return ( <ClerkProvider {...pageProps}> <SignIn appearance={{ elements: { formButtonPrimary: { fontSize: 14, textTransform: "none", backgroundColor: "#611BBD", "&:hover, &:focus, &:active": { backgroundColor: "#49247A", }, }, }, }} path="/sign-in" /> </ClerkProvider> ); } export default MyApp;
Next steps
Here are a few resources you can utilize to customize your Clerk components further:
Last updated on March 15, 2024