I'm trying to create a theme system using Tailwind, React, and NextJS, and I'm doing so by updating the class name of a given tag to the current theme name. This works fine for tags within the main app component, but how can I dynamically change the class of the body tag once my theme state changes?
For example, if I have theme A selected then the <body>
should have a background color of black. If theme B is selected then <body>
should have a background color of red.
Themes will change based on state, so I imagine it should look something like this:
const App = () => {
const theme = themeGetter()
return (
<body className={theme}>
...
</body>
)
}
But obviously, this won't actually change the classname of the body. Is there an easy way to accomplish this?
I encountered the exact same problem. But the thing is the html and body tags are only defined in the Root layout. And to dynamically change className in body tag would mean using state (useState). And this would mean setting Root layout component to be client rendered (use Client), which goes against Next.js server rendered philosophy, and would even later cause problems when trying to export "metadata".
My crude workaround (considering my current knowledge base) was to add an extra div immediately following body, and place in the page.js file. This div is to contain all code, thus it’s acting like an extra body. Div can now be manipulated with useState to achieve coding intentions.
<html>
<body>
<div id="root" className={theme}>
</div>
</body>
</html>
I.e: The most outward element in your page.js app folder file will be
<div id="root" className={theme}></div>
Thus Root layout is left alone as
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}