āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā š shadcn/directory/clerk/clerk-docs/guides/customizing-clerk/appearance-prop/themes ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
Clerk currently offers six prebuilt themes:
Applied by default when no other theme is provided.
<div style={{padding: "1rem 0", filter: "drop-shadow(rgba(0, 0, 0, 0.16) 0px 12px 24px)"}}> {{ style: { maxWidth: '400px', width: '100%' } }} </div>[!IMPORTANT] This theme is compatible with Tailwind CSS v4 usage. If you need support for Tailwind CSS v3, pass the shadcn variables manually to your
<ClerkProvider />'svariablesobject.
When using the shadcn/ui library, you can use the shadcn theme to apply the shadcn/ui styles to your Clerk components. This will adapt to both light and dark mode automatically.
[!IMPORTANT] It's recommended to also import the
shadcn.cssfile within yourglobal.cssfile. Tailwind scans source files as plain text to detect which classes to generate - classes that only exist in external configurations won't be included in the final CSS.@import 'tailwindcss'; @import '@clerk/themes/shadcn.css';
<Tabs items={["Light mode", "Dark mode"]}>
<div style={{padding: "1rem 0", filter: "drop-shadow(rgba(0, 0, 0, 0.16) 0px 12px 24px)"}}> {{ style: { maxWidth: '400px', width: '100%' } }} </div> <div style={{padding: "1rem 0", filter: "drop-shadow(rgba(0, 0, 0, 0.16) 0px 12px 24px)"}}> {{ style: { maxWidth: '400px', width: '100%' } }} </div> </Tabs>This theme is a stripped down "Default" theme that removes some more advanced styling techniques, making it easier to apply your own custom styles.
To use the simple theme, set theme to simple:
<ClerkProvider
appearance={{
theme: 'simple',
}}
/>
<div style={{padding: "1rem 0"}}>
{{ style: { maxWidth: '400px', width: '100%' } }}
</div>
To get started, install the @clerk/themes package.
<CodeBlockTabs options={["npm", "yarn", "pnpm", "bun"]}>
npm install @clerk/themes
yarn add @clerk/themes
pnpm add @clerk/themes
bun add @clerk/themes
</CodeBlockTabs>
To use a theme, import it from @clerk/themes and pass it to the appearance prop of a Clerk component.
To apply a theme to all Clerk components, pass the appearance prop to the <ClerkProvider> component. The appearance prop accepts the property theme, which can be set to a theme.
In the following example, the "Dark" theme is applied to all Clerk components.
<Tabs items={["Next.js", "React", "Astro", "Remix", "Vue", "Nuxt"]}> <Tab> <CodeBlockTabs options={["App Router", "Pages Router"]}> ```tsx {{ filename: '/src/app/layout.tsx', mark: [2, [7, 9]] }} import { ClerkProvider } from '@clerk/nextjs' import { dark } from '@clerk/themes'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
appearance={{
theme: dark,
}}
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
)
}
```
```tsx {{ filename: '_app.tsx', mark: [2, 8, 9, 10] }}
import { ClerkProvider } from '@clerk/nextjs'
import { dark } from '@clerk/themes'
import type { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return (
<ClerkProvider
appearance={{
theme: dark,
}}
>
<Component {...pageProps} />
</ClerkProvider>
)
}
export default MyApp
```
</CodeBlockTabs>
</Tab>
<Tab>
```tsx {{ filename: 'app.tsx', mark: [3, [14, 16]] }}
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={{
theme: dark,
}}
publishableKey={clerkPubKey}
>
<div>Hello from clerk</div>
</ClerkProvider>
)
}
export default App
```
</Tab>
<Tab>
```js {{ filename: 'astro.config.mjs', mark: [2, [7, 9]] }}
import clerk from '@clerk/astro'
import { dark } from '@clerk/themes'
export default defineConfig({
integrations: [
clerk({
appearance: {
theme: dark,
},
}),
],
})
```
</Tab>
<Tab>
```tsx {{ filename: 'app/root.tsx', mark: [3, [36, 38]] }}
// 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: {
theme: dark,
},
})
```
</Tab>
<Tab>
```ts {{ filename: 'src/main.ts', mark: [4, [8, 10]] }}
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
import { dark } from '@clerk/themes'
const app = createApp(App)
app.use(clerkPlugin, {
appearance: {
theme: dark,
},
})
app.mount('#app')
```
</Tab>
<Tab>
```ts {{ filename: 'nuxt.config.ts', mark: [1, [6, 8]] }}
import { dark } from '@clerk/themes'
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
clerk: {
appearance: {
theme: dark,
},
},
})
```
</Tab>
</Tabs>
You can also stack themes by passing an array of themes to the theme 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.
<Tabs items={["Next.js", "React", "Astro", "Remix", "Vue", "Nuxt"]}> <Tab> <CodeBlockTabs options={["App Router", "Pages Router"]}> ```tsx {{ filename: '/src/app/layout.tsx', mark: [2, [7, 9]] }} import { ClerkProvider } from '@clerk/nextjs' import { dark, neobrutalism } from '@clerk/themes'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
appearance={{
theme: [dark, neobrutalism],
}}
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
)
}
```
```tsx {{ filename: '_app.tsx', mark: [2, [8, 10]] }}
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={{
theme: [dark, neobrutalism],
}}
>
<Component {...pageProps} />
</ClerkProvider>
)
}
export default MyApp
```
</CodeBlockTabs>
</Tab>
<Tab>
```tsx {{ filename: 'app.tsx', mark: [3, [14, 16]] }}
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={{
theme: [dark, neobrutalism],
}}
publishableKey={clerkPubKey}
>
<div>Hello from clerk</div>
</ClerkProvider>
)
}
export default App
```
</Tab>
<Tab>
```js {{ filename: 'astro.config.mjs', mark: [2, [7, 9]] }}
import clerk from '@clerk/astro'
import { dark, neobrutalism } from '@clerk/themes'
export default defineConfig({
integrations: [
clerk({
appearance: {
theme: [dark, neobrutalism],
},
}),
],
})
```
</Tab>
<Tab>
```tsx {{ filename: 'app/root.tsx', mark: [3, [36, 38]] }}
// 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: {
theme: [dark, neobrutalism],
},
})
```
</Tab>
<Tab>
```ts {{ filename: 'src/main.ts', mark: [4, [8, 10]] }}
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
import { dark, neobrutalism } from '@clerk/themes'
const app = createApp(App)
app.use(clerkPlugin, {
appearance: {
theme: [dark, neobrutalism],
},
})
app.mount('#app')
```
</Tab>
<Tab>
```ts {{ filename: 'nuxt.config.ts', mark: [1, [6, 8]] }}
import { dark, neobrutalism } from '@clerk/themes'
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
clerk: {
appearance: {
theme: [dark, neobrutalism],
},
},
})
```
</Tab>
</Tabs>
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.
<Tabs items={["Next.js", "React", "Astro", "Remix", "Vue", "Nuxt"]}> <Tab> <CodeBlockTabs options={["App Router", "Pages Router"]}> ```tsx {{ filename: '/src/app/layout.tsx', mark: [2, [7, 10]] }} import { ClerkProvider } from '@clerk/nextjs' import { dark, neobrutalism } from '@clerk/themes'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
appearance={{
theme: dark,
signIn: { theme: neobrutalism },
}}
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
)
}
```
```tsx {{ filename: '_app.tsx', mark: [2, [8, 11]] }}
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={{
theme: dark,
signIn: { theme: neobrutalism },
}}
>
<Component {...pageProps} />
</ClerkProvider>
)
}
export default MyApp
```
</CodeBlockTabs>
</Tab>
<Tab>
```tsx {{ filename: 'app.tsx', mark: [3, [14, 17]] }}
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={{
theme: dark,
signIn: { theme: neobrutalism },
}}
publishableKey={clerkPubKey}
>
<div>Hello from clerk</div>
</ClerkProvider>
)
}
export default App
```
</Tab>
<Tab>
```js {{ filename: 'astro.config.mjs', mark: [2, [7, 10]] }}
import clerk from '@clerk/astro'
import { dark } from '@clerk/themes'
export default defineConfig({
integrations: [
clerk({
appearance: {
theme: dark,
signIn: { theme: neobrutalism },
},
}),
],
})
```
</Tab>
<Tab>
```tsx {{ filename: 'app/root.tsx', mark: [3, [36, 39]] }}
// 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: {
theme: dark,
signIn: { theme: neobrutalism },
},
})
```
</Tab>
<Tab>
```ts {{ filename: 'src/main.ts', mark: [4, [8, 11]] }}
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
import { dark, neobrutalism } from '@clerk/themes'
const app = createApp(App)
app.use(clerkPlugin, {
appearance: {
theme: dark,
signIn: { theme: neobrutalism },
},
})
app.mount('#app')
```
</Tab>
<Tab>
```ts {{ filename: 'nuxt.config.ts', mark: [1, [6, 9]] }}
import { dark, neobrutalism } from '@clerk/themes'
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
clerk: {
appearance: {
theme: dark,
signIn: { theme: neobrutalism },
},
},
})
```
</Tab>
</Tabs>
To apply a theme to a single Clerk component, pass the appearance prop to the component. The appearance prop accepts the property theme, which can be set to a theme.
<Tabs items={["Next.js", "React", "Astro", "Remix", "Vue", "Nuxt"]}> <Tab> <CodeBlockTabs options={["App Router", "Pages Router"]}> ```tsx {{ filename: 'app/sign-in/[[...sign-in]]/page.tsx', mark: [2, [7, 9]] }} import { SignIn } from '@clerk/nextjs' import { dark } from '@clerk/themes'
export default function Page() {
return (
<SignIn
appearance={{
theme: dark,
}}
/>
)
}
```
```tsx {{ filename: '/pages/sign-in/[[...index]].tsx', mark: [2, [6, 8]] }}
import { SignIn } from '@clerk/nextjs'
import { dark } from '@clerk/themes'
const SignInPage = () => (
<SignIn
appearance={{
theme: dark,
}}
/>
)
export default SignInPage
```
</CodeBlockTabs>
</Tab>
<Tab>
```tsx {{ filename: '/src/sign-in/[[...index]].tsx', mark: [2, [6, 8]] }}
import { SignIn } from '@clerk/clerk-react'
import { dark } from '@clerk/themes'
const SignInPage = () => (
<SignIn
appearance={{
theme: dark,
}}
/>
)
export default SignInPage
```
</Tab>
<Tab>
```astro {{ filename: 'pages/sign-in.astro', mark: [3, [9, 11]] }}
---
import { SignIn } from '@clerk/astro/components'
import { dark } from '@clerk/themes'
---
<SignIn
appearance={{
theme: dark,
}}
/>
```
</Tab>
<Tab>
```tsx {{ filename: 'app/routes/sign-in/$.tsx', mark: [2, [9, 11]] }}
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={{
theme: dark,
}}
/>
</div>
)
}
```
</Tab>
<Tab>
```vue {{ filename: 'src/pages/sign-in.vue' }}
<script setup lang="ts">
import { SignIn } from '@clerk/vue'
import { dark } from '@clerk/themes'
</script>
<template>
<SignIn :appearance="{ theme: dark }" />
</template>
```
</Tab>
<Tab>
```vue {{ filename: 'pages/sign-in.vue' }}
<script setup lang="ts">
// Components are automatically imported
import { dark } from '@clerk/themes'
</script>
<template>
<SignIn :appearance="{ theme: dark }" />
</template>
```
</Tab>
</Tabs>
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
variablesproperty, see the Variables docs.
<Tabs items={["Next.js", "React", "Astro", "Remix", "Vue", "Nuxt"]}> <Tab> <CodeBlockTabs options={["App Router", "Pages Router"]}> ```tsx {{ filename: '/src/app/layout.tsx', mark: [2, [7, 14]] }} import { ClerkProvider } from '@clerk/nextjs' import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
appearance={{
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'green' },
},
}}
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
)
}
```
```tsx {{ filename: '_app.tsx', mark: [2, [8, 15]] }}
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={{
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
}}
>
<Component {...pageProps} />
</ClerkProvider>
)
}
export default MyApp
```
</CodeBlockTabs>
</Tab>
<Tab>
```tsx {{ filename: 'app.tsx', mark: [3, [14, 21]] }}
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={{
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
}}
publishableKey={clerkPubKey}
>
<div>Hello from clerk</div>
</ClerkProvider>
)
}
export default App
```
</Tab>
<Tab>
```js {{ filename: 'astro.config.mjs', mark: [2, [7, 14]] }}
import clerk from '@clerk/astro'
import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'
export default defineConfig({
integrations: [
clerk({
appearance: {
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
},
}),
],
})
```
</Tab>
<Tab>
```tsx {{ filename: 'app/root.tsx', mark: [3, [36, 43]] }}
// 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: {
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
},
})
```
</Tab>
<Tab>
```ts {{ filename: 'src/main.ts', mark: [4, [8, 15]] }}
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'
const app = createApp(App)
app.use(clerkPlugin, {
appearance: {
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
},
})
app.mount('#app')
```
</Tab>
<Tab>
```ts {{ filename: 'nuxt.config.ts', mark: [1, [6, 13]] }}
import { dark, neobrutalism, shadesOfPurple } from '@clerk/themes'
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
clerk: {
appearance: {
theme: [dark, neobrutalism],
variables: { colorPrimary: 'blue' },
signIn: {
theme: [shadesOfPurple],
variables: { colorPrimary: 'blue' },
},
},
},
})
```
</Tab>
</Tabs>ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā