sc0ria
sc0ria

Reputation: 21

How to force a theme on a single page using Next.js 13 appDir? Using Next-Theme

I have setup my website using Next.js 13 appDir and I am using next-theme's way of working around appDir as you can see in this issue: https://github.com/pacocoursey/next-themes/issues/152

What I want to do is to force a theme on the home page and allow the theme to toggle between dark and light mode. I saw that next-theme's doc has a section explaining how to do it on the Pages directory:https://www.npmjs.com/package/next-themes#:~:text=Force%20page%20to%20a%20theme

It seems like you just have to set a theme variable on the page component and pass it up to the layout so you can pass it as a prop to the theme provider.

How can I do that using appDir?

page.tsx

const Home = async () => {
  return (
    <div className="overflow-hidden bg-cloud">
      {/*... my code*/}
    </div>
  )
}

Home.theme = 'light'

export default Home

layout.tsx

import '@/styles/globals.css'

import { IBM_Plex_Sans } from 'next/font/google'

import Providers from './providers'

const IBMPlexSans = IBM_Plex_Sans({
  weight: ['100', '200', '300', '400', '700'],
  subsets: ['latin'],
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={`${IBMPlexSans.className} text-night-dark`}>
        <Providers defaultTheme="system" enableSystem>
          {children}
        </Providers>
      </body>
    </html>
  )
}

providers.tsx

'use client'

import { ThemeProvider as NextThemeProvider } from 'next-themes'
import { ThemeProviderProps } from 'next-themes/dist/types'

const Providers = ({ children, ...props }: ThemeProviderProps) => {
  return <NextThemeProvider {...props}>{children}</NextThemeProvider>
}

export default Providers

Tried using the force property on theme provider but makes it impossible to toggle between dark mode and light mode in the subsequent pages.

Upvotes: 0

Views: 3257

Answers (1)

Akuya Ekorot
Akuya Ekorot

Reputation: 11

The strategy I use to solve this is wrapping that page with a layout or with a client component that uses the setTheme function returned from the useTheme hook.

page-theme.tsx

'use client';

import { useTheme } from 'next-themes';

export default function PageTheme({ children }: {children: React.ReactNode}) {
  const { setTheme } = useTheme();

  useEffect(() => {
    setTheme('light'); //set your theme here after component mounts
  }, []);

  return <div>{children</div>;
}

page.tsx

const Home = async () => {
  return (
    <PageTheme>
      <div className="overflow-hidden bg-cloud">
        {/*... my code*/}
      </div>
    </PageTheme>
  );
}

export default Home

Upvotes: 1

Related Questions