Docs

Themes

Clerk currently offers four pre-built themes:

Default theme

Applied by default when no other theme is provided.

A sign-in form with a light theme
A sign-in form with a dark theme
A sign-in form with a purple and yellow theme
A sign-in form with a neobrutalist red theme

Usage

  1. To get started, install the @clerk/themes package.

    terminal
    npm install @clerk/themes
    terminal
    yarn add @clerk/themes
    terminal
    pnpm add @clerk/themes
  2. To use a theme, import it from @clerk/themes and pass it to the appearance prop of a Clerk component.

Apply a theme to all Clerk components

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 following example, the "Dark" theme is applied to all Clerk components.

/src/app/layout.tsx
import { 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.tsx
import { 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.tsx
import 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,
  },
});

Apply multiple themes

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 following example, the "Dark" theme is applied first, then the "Neobrutalism" theme is applied on top of it.

/src/app/layout.tsx
import { 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.tsx
import { 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.tsx
import 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]
  },
});

Apply a theme to all instances of a Clerk component

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 following example, the "Neobrutalism" theme is applied to all instances of the <SignIn /> component.

/src/app/layout.tsx
import { 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.tsx
import { 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.tsx
import 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 },
  },
});

Apply 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.tsx
import { 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]].tsx
import { 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]].tsx
import { 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/$.tsx
import { 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 following example, the primary color of the themes are customized.

Important

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.tsx
import { 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.tsx
import { 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.tsx
import 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' }
    }
  }}
});

Feedback

What did you think of this content?