Reputation: 394
I have a nextjs 13 application and I'm using Clerk for authentication.
I'm trying to match the theme of the app to the ClerkProvider
component.
I used the useTheme
hook from next-themes
to get the resolvedTheme
and assign the theme accordingly, but that required converting the layout.tsx
into a client component which misses up with the metadata. I'm wondering if there is a better way to handle this.
Here is my code:
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { ClerkProvider } from "@clerk/nextjs";
import { ThemeProvider } from "@/components/theme-provider";
import { useTheme } from "next-themes";
import { dark } from "@clerk/themes";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const { resolvedTheme } = useTheme();
return (
<ClerkProvider
appearance={{
baseTheme: resolvedTheme === "dark" ? dark : undefined,
}}
>
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
</ClerkProvider>
);
}
Upvotes: 2
Views: 3001
Reputation: 1
well clerk components(SignIn, SignUp, UserButton) accpet apperence
as props. you can pass theme to those components.
"use clients";
import { useTheme } from 'next-themes'
import { dark } from '@clerk/theme'
import { UserButton } from '@clerk/nextjs';
export default function Page() {
const { theme } = useTheme();
const apprence = useMemo(()=>{
let result: ComponentProps<typeof UserButton>['apprence'];
if(theme === 'dark') {
result = {
baseTheme: dark
}
}
return result;
}, [theme])
return (
<UserButton apprence={apprence} userProfileProps={{apprence}} />
)
}
Upvotes: 0
Reputation: 110
Rather than setting it from Clerk → ThemeProvider, I suggest to do it the other way round.
As mentioned in the answer by Ahmad Mughal, you won't be able to set the appearance in the ClerkProvider globally, since it's expected to run only on the server.
You can however set the appearance on the level of Clerk components where you can use useTheme()
(if you declare the page a client component with 'use client').
A page like this will render the appearance of the Clerk SignIn component according to the current theme from the ThemeProvider:
"use client";
import { SignIn } from "@clerk/nextjs";
import { dark } from "@clerk/themes";
import { useTheme } from "next-themes";
const PageWithSignIn = () => {
const { currentTheme } = useTheme();
return (
<SignIn
appearance={{
baseTheme: currentTheme === "dark" ? dark : undefined,
}}
/>
);
};
export default Page;
Upvotes: 7
Reputation: 1
ClerkProvider requires to be work only inside of a Server Component so using it inside a client component just makes it complain about useRouter.
Upvotes: 0
Reputation: 4916
Move your client code into a client component with children prop:
"use client"
// ...
export function Providers({children}) {
const { resolvedTheme } = useTheme();
return <ClerkProvider
appearance={{
baseTheme: resolvedTheme === "dark" ? dark : undefined,
}}
>
{children}
</ClerkProvider>
}
Then render this component in your layout.tsx
export function RootLayout() {
return <html>
<head>...</head>
<body>
<Providers>
...
</Providers>
</body>
</html>
}
Upvotes: 0