Theme Switcher in Next.js
Toggle between dark and light theme without wrapping children in context
5 min read
In web applications, theming enhances user experience by offering personalization and visual appeal. Typically, a ThemeProvider
context manages themes throughout the application. This works well for fully client-side apps. However, developers need a solution for apps that combine client and server components, where theming depends on color-schema
or className
.
With , wrapping children in a Context automatically makes them client components. This blog post explores how to implement a ThemeProvider
that avoids the need to wrap the entire application in a context provider, addressing the challenges of mixed client-server environments.
Generally speaking; implementing a theme switcher involves three main steps:
- Create Theme Provider Component: Develop a custom
ThemeProvider
component that handles theme switching and - Use Theme Switcher: Integrate the
ThemeProvider
component into your application to switch theme. - Integrate Theme Provider: Integrate the
ThemeProvider
component into your application layout to make sure client theming is synced with server on hydration.
The old way
1. Create Theme Provider Component
In a typical React application, you would wrap the entire application in a ThemeProvider
context provider. This approach works well for client-side applications but can be cumbersome for Next.js applications that combine client and server components.
2. Use Theme Switcher
To accompany the ThemeProvider
, you would need a ThemeSwitcher
component to toggle between themes. You can already see the relianse on useTheme
hook from next-themes
package to get the current theme and toggle it.
3. Integrate Theme Provider
What happens now is that in our application we will need to wrap all of our content with the ThemeProvider
as shown below.
The new way
1. Create Theme Provider Component
You can notice the integration of the useEffect
hook to set the cookie with the theme choice. This will make sure that the theme choice is persisted even after the user refreshes the page.
2. Use Theme Switcher
The ThemeSwitcher
component is now simplified and does not require the useEffect
hook to check if the component is mounted. This is because the ThemeProvider
component automatically makes its children client components. You can also notice the use of the useTheme
hook to get the current theme and toggle it.
3. Integrate Theme Provider
In the App.js
file, you can see that the ThemeProvider
component is now dynamically imported using the dynamic
function from next/dynamic
. This ensures that the ThemeProvider
component is only rendered on the client-side. Moreover, the theme choice is now persisted in a cookie. This offers a cleaner and more efficient way to manage themes in your application without making complete application a client component.