Next 13 "app" vs pages support?
I am using Nextjs and Tailwind and experimenting with migrating a small app to the new app directory in Nextjs 13. I am struggling to figure out how to make dark/light mode work. I am using this library with the old system with the "pages" directory and a custom _app.js. I have tried this but it doesn't work:
"use client";
import "../styles/globals.css";
import { ThemeProvider } from "next-themes";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ThemeProvider>
<html lang="en">
<head />
<body
className="px-4 sm:px-8 bg-white lg:px-24 dark:bg-gray-900"
>
{children}
</body>
</html>
</ThemeProvider>
);
}
You need to make a provider component and wrap { children } in the root layout. You also need to (AFAIK) "npm i next-themes@npm:@wits/next-themes"
something like this:
Providers.tsx
'use client'
import { ReactNode } from "react";
import { ThemeProvider } from '@wits/next-themes'
import { OtherProvider } from "./context/OtherContext";
// * Because layout.tsx is only rendered on the server-side, we can use the
// * ThemeProvider and OtherProvider components directly in the RootLayout
// * component.
// * This is not possible in the app.tsx file because it is rendered
// * on both the server-side and the client-side.
export default function Providers({ children }: { children: ReactNode }) {
return (
<ThemeProvider attribute="class">
<OtherProvider>
{children}
</OtherProvider>
</ThemeProvider>
)
}
layout.tsx
import { ReactNode } from "react";
import { ServerThemeProvider } from "next-themes";
import { Quicksand } from '@next/font/google'
import Providers from "./Providers";
import Header from "./components/Header";
import "./output.css";
const quicksand = Quicksand()
// * The ServerThemeProvider component is used to ensure that the correct
// * theme is applied on the server-side. It is not required on the client-side.
// * It wraps the html element and takes an attribute prop which is the attribute
// * that will be used to set the theme class on the html element.
// * The default value is "class".
// * The theme class will be applied to the html element on the server-side
// * and then removed on the client-side to prevent a flash of unstyled content.
// * The Providers component wraps the app and provides the context for the
// * useTheme and usePokemon hooks.
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<ServerThemeProvider attribute="class">
<html lang="en" className={quicksand.className}>
<head />
<body>
<Providers>
<Header />
{children}
</Providers>
</body>
</html>
</ServerThemeProvider>
)
}
hope this helps
This is awesome - works perfectly!
Worked for me as well 🙌🏼
After a lot of reading on this subject, I can say that this works for me as well! However, I have a strange bug. Sometimes, after I switched theme, some elements are randomly selected in the page, whether it is images or yet just part of text. I'm wondering if it is a matter of hardware or just a strange glitch resulting of hydration. It is not a big deal, but of course it would be better without it for UX.
@giuseppe-g-gelardi thx for sharing your solution.