VOOZH about

URL: https://blog.logrocket.com/theming-in-next-js-with-styled-components-and-usedarkmode/

⇱ Theming in Next.js with styled-components and useDarkMode - LogRocket Blog


2021-02-11
1434
#css
Nefe Emadamerho-Atori
34282
👁 Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

Color is arguably the second-most critical aspect of your app, after functionality. The right color scheme helps you set the mood for your app and shows users how to interact with it.

👁 theming-use-dark-mode-styled-components-template

In many cases, enabling your users to choose their preferred color scheme and switch between themes can be a selling point. But you don’t want to overwhelm your user with a multitude of themes to choose from. More often than not, light and dark themes are all you need to create a beautiful UI.

In this tutorial, we’ll show you how to efficiently implement dark mode and theme a Next.js app using the styled-components library and the useDarkMode Hook.

We’ll cover the following:

🚀 Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

What is dark mode?

Dark mode is the color scheme of any interface that displays light text and interface elements on a dark background, which makes the screen a little easier to look at on mobile phones, tablets, and computers. Dark mode reduces the light emitted by the screen while maintaining the minimum color-contrast ratios required for readability.

Light mode, which displays darker text atop a bright background, is the much more prevalent color scheme.

Benefits of using dark mode include:

  • Energy savings
  • Less strain on the eyes
  • It looks cool

What is styled-components?

styled-components is a CSS-in-JS library that drastically improves developer experience for the modern frontend developer while providing a near-perfect user experience. Aside from giving developers the ability to write component-scoped CSS, styled-components comes with a number of other benefits, including:

  • Automatic vendor prefixing
  • Unique class names for each styled component
  • Easier maintenance of styles — developers can delete or modify styles without affecting other components

Theming with styled-components

Begin by setting up a Next.js app using create-next-app and then installing the styled-components package.

npm i styled-components

To use styled-components in a Next.js app, go into the _app.js file, import the ThemeProvider component, and wrap the app with the ThemeProvider.

ThemeProvider accepts a theme object as a prop and then re-exposes that object dynamically to any styled component deeper in your component tree.

import { ThemeProvider } from "styled-components"

Next, create a ThemeConfig.js file.

import { createGlobalStyle} from "styled-components"

export const lightTheme = {
 body: '#FFF',
 text: '#363537',
 toggleBorder: '#FFF',
 background: '#363537',
}

export const darkTheme = {
 body: '#363537',
 text: '#FAFAFA',
 toggleBorder: '#6B8096',
 background: '#999',
}

export const GlobalStyles = createGlobalStyle`
 body {
 background: ${({ theme }) => theme.body};
 color: ${({ theme }) => theme.text};
 font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif;
 transition: all 0.50s linear;
 }
`

Here, we define lightTheme, darkTheme, and GlobalStyles. We’ll need them to theme the app later on. In lightTheme, we define light mode styles. In darkTheme, we define the dark mode styles.

We also import createGlobalStyle from styled-components. This method generates a React component, which, when added to the component tree, injects global styles into the document.

In GlobalStyles, we define the styles for the body of the app. We want the background color and text color to change as we switch from light mode to dark mode.

We take the context of the currently active theme, whether lightTheme or darkTheme, from the ThemeProvider, and use that theme’s styles to determine the background color and text color of the app. This way, the theme of the app changes dynamically as we switch from light mode to dark mode.


Over 200k developers use LogRocket to create better digital experiences

👁 Image
Learn more →

Now that we’ve set up the light and dark themes for the app, we need to implement toggle functionality to switch between light and dark modes.

To do this, create a theme state in the _app.js file and set up a toggleTheme function:

const [theme, setTheme] = useState("light") 

const toggleTheme = () => {
 theme == 'light' ? setTheme('dark') : setTheme('light')
}

We pass the theme state into the ThemeProvider and, depending on the state, switch between lightTheme and darkTheme.

toggleTheme is the function responsible for checking the theme state from light to dark. Then, we pass the toggleTheme function into a button:

import { useState } from "react"
import { ThemeProvider } from "styled-components";

const [theme, setTheme] = useState("light") 

const toggleTheme = () => {
 theme == 'light' ? setTheme('dark') : setTheme('light')
}

return (
 <ThemeProvider>
 <button onClick={toggleTheme}>Switch Theme</button>
 <Component {...pageProps} />
 </ThemeProvider>
) 

So far, we’ve defined the lightTheme, darkTheme, GlobalStyles, and toggle functionality for the app. Now, let’s bring everything together into the _app.js file:

import { useState } from "react"
import { ThemeProvider } from "styled-components";
import { lightTheme, darkTheme, GlobalStyles } from "../themeConfig" 

function MyApp({ Component, pageProps }) {
 const [theme, setTheme] = useState("light") 

 const toggleTheme = () => {
 theme == 'light' ? setTheme('dark') : setTheme('light')
 }

 return (
 <ThemeProvider theme={theme == 'light' ? lightTheme : darkTheme}>
 <GlobalStyles />
 <button onClick={toggleTheme}>Switch Theme</button>
 <Component {...pageProps} />
 </ThemeProvider&gt;
 ) 
}
export default MyApp

With this, we’ve successfully set up theming for our Next.js app using styled-components.

Theming with the useDarkMode Hook

The useDarkMode Hook is a useful styling alternative that can be explored for theming purposes. When used in combination with styled-components, it makes theming apps easy and fun.

With the useDarkMode Hook, we don’t need to set a theme state or create a toggleTheme function that switches from light to dark mode. useDarkMode takes care of that for us.

To start using the useDarkMode hook, first install it:

npm i use-dark-mode

Next, create a new instance of the Hook and begin using it. I did this in my _app.js file:

const darkmode = useDarkMode(true)

The darkmode object we created has several properties. What we need is its value property. This is a boolean that checks whether the dark mode is active.

const theme = darkmode.value ? darkTheme : lightTheme

return (
 <ThemeProvider theme={theme}>
 <GlobalStyles />
 <button onClick={darkmode.toggle}>Switch Mode</button>
 <button onClick={darkmode.enable}>Dark Mode</button>
 <button onClick={darkmode.disable}>Light Mode</button>
 <Component {...pageProps} />
 </ThemeProvider>
) 

Based on the value of darkmode, we switch between lightTheme and darkTheme and pass the active theme to the theme constant. We pass this active theme into the ThemeProvider‘s theme prop.


More great articles from LogRocket:


We to set up buttons to switch between light and dark mode, The darkmode object comes with enable(), disable(), and toggle() functionality out of the box.

With that, we’ve themed our app by combining styled-components with useDarkMode.

Next.js renders pages on the server. While this has its benefits, it also comes with a tradeoff: SSR doesn’t know about client-specific preferences, such as prefers-color-scheme. This means when the page loads on the server, the correct theme isn’t selected initially. This causes a “flicker” between light and dark themes.

To fix this, we set up an isMounted state and set it to false.

const [isMounted, setIsMounted] = useState(false)

useEffect(() => {
 setIsMounted(true)
}, [])

return (
 <ThemeProvider theme={theme}>
 <GlobalStyles />
 ...
 {isMounted && <Component {...pageProps} />}
 </ThemeProvider>
) 

We use the useEffect to determine when the app has mounted and display it only when isMounted is true. This way removed the brief flicker.

Let’s put it all together:

import { useState, useEffect } from "react"
import useDarkMode from "use-dark-mode"
import { ThemeProvider } from "styled-components";
import { lightTheme, darkTheme, GlobalStyles } from "../themeConfig"

function MyApp({ Component, pageProps }) {
 const [isMounted, setIsMounted] = useState(false)
 const darkmode = useDarkMode(true)
 const theme = darkmode.value ? darkTheme : lightTheme

 useEffect(() => {
 setIsMounted(true)
 }, [])

 return (
 <ThemeProvider theme={theme}>
 <GlobalStyles />
 <button onClick={darkmode.toggle}>Switch Mode</button>
 <button onClick={darkmode.enable}>Dark Mode</button>
 <button onClick={darkmode.disable}>Light Mode</button>
 {isMounted && <Component {...pageProps} />}
 </ThemeProvider>
 ) 
}

export default MyApp

Using useDarkMode and CSS

Depending on your project’s needs and requirements, you may not need to use a CSS-in-JS library like styled-components just to theme your app. You can alternatively theme your apps with useDarkMode using CSS.

To use CSS to theme your app with useDarkMode, create body.light-mode and body.dark-mode classes in your globals.css file. These are special classes recognized by useDarkMode.

body.dark-mode {
 color: #fff;
 background: #363537;

//dark mode styles
}

body.light-mode {
 color: #363537;
 background: #fafafa;

//light mode styles
} 

Copy the styles you defined in lightTheme and darkTheme into those classes. It’s as quick and simple as that.

Conclusion

The useDarkMode Hook makes theming apps easier and faster, whether it’s used in combination with a CSS-in-JS library such as styled-components or with CSS.

When it comes to theming your Next.js apps, you have plenty of options.

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

👁 LogRocket Dashboard Free Trial Banner

LogRocket lets you replay user sessions, eliminating guesswork around why bugs happen by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks.

LogRocket's Galileo AI watches sessions for you, instantly identifying and explaining user struggles with automated monitoring of your entire product experience.

Modernize how you debug web and mobile apps — start monitoring for free.

👁 Image
👁 Image
👁 Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

How to build a virtual engineering team with Gemini CLI subagents

Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.

👁 Image
Emmanuel John
Jun 18, 2026 ⋅ 10 min read

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

👁 Image
Emmanuel John
Jun 17, 2026 ⋅ 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

👁 Image
Chizaram Ken
Jun 16, 2026 ⋅ 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.

👁 Image
Ikeh Akinyemi
Jun 12, 2026 ⋅ 6 min read
View all posts

Hey there, want to help make our blog better?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now