Next.js 13 appDir support
See original GitHub issueOpening an issue to track support for Next.js 13’s appDir
and server components.
Currently, it’s possible to use next-themes
within appDir
with the following pattern:
// app/layout.tsx
import * as React from 'react'
import { Providers } from './providers'
import './globals.css'
export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<html>
<head>
</head>
<body>
<Providers>
{children}
</Providers>
</body>
</html>
)
}
// app/providers.tsx
'use client'
import { ThemeProvider } from 'next-themes'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider>
{children}
</ThemeProvider>
)
}
This works for the most part, including accessing and changing the theme via useTheme
.
However, during next dev
, we get the following console error hinting at hydration problems:
Warning: Extra attributes from the server: data-theme,style
at html
at ReactDevOverlay (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:53:9)
at HotReload (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:19:11)
at Router (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/app-router.js:74:11)
at ErrorBoundaryHandler (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:28:9)
at ErrorBoundary (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:40:11)
at AppRouter
at ServerRoot (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:113:11)
at RSCComponent
at Root (webpack-internal:///./node_modules/.pnpm/next@13.0.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:130:11)
And during production (hosted on Vercel), the following hydration errors seem to randomly appear regardless of how much I pair down the example so long as I’m using next-themes
in this way:
Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
at zh (796-3c8db907cc96f9a4.js:9:55756)
at ...
#145 looks to be a cookies-based approach to solving this issue, but the PR looks stalled and I’m not sure if it’s a working solution or even the best approach. So I wanted to open up an issue here to track suggestions & progress.
Thanks!
Issue Analytics
- State:
- Created 10 months ago
- Reactions:10
- Comments:24
Top GitHub Comments
Okay, just published
0.2.14
which should fix more hydration errors. (Maybe all of them? 🤞)That pr should be updated to work with Next.js
13.0.3
now. I’m still looking into making further improvements, but you can test the changes through the npm package @wits/next-themes prior to the pr being merged. (Or try runningnpm i "next-themes@npm:@wits/next-themes"
if you want to keep the same imports in your code.)I’d like to provide some more context on why the current approach uses cookies. Unfortunately, trying to get this working in the app directory without ensuring that the server is rendering the same
<html>
attributes results in errors. So I reached out to @pacocoursey as well as some members of the Next.js team before starting this work, and they agreed that a cookie-based approach would be the right move.next/script
is a great call! It wasn’t available for the app directory when I first started writing these changes, but it looks like using it withstategy="beforeInteractive"
works here. However, doing so inside of a client component (like the existingThemeProvider
still causes it to run too late and the page will flicker un-themed content. Also, by default, that script relies onwindow.matchMedia
to determine the system theme of the user. That isn’t available on the server, so without cookies we still get errors due to a mismatch between client and server rendering during fast refreshes.