DEV Community

Cover image for Styling Your Site with Next.js and MUI: Creating a Dynamic Theme Switcher
Douglas Porto
Douglas Porto

Posted on

Styling Your Site with Next.js and MUI: Creating a Dynamic Theme Switcher

Hello, devs! ✌🏾

As promised, I'm back to posting more frequently. Today, we're kicking off a series on using Material-UI with Next.js to create a simple switch between light and dark themes.

Starting a Next.js Project

Getting started is straightforward. Just follow the steps in the Next.js documentation:

npx create-next-app@latest

Once Next.js is installed, let's clean up the directory. Remove the files globals.css and page.module.css that we won't use.

In your page.tsx, the code should look like this:

export default function Home() {
  return <div>Hello world</div>
}
Enter fullscreen mode Exit fullscreen mode

And don't forget to remove the import import "./globals.css"; in the layout.tsx file.

Installing Material-UI (MUI)

To get started with MUI, visit the Getting started section of the documentation. You can use npm, yarn, or pnpm for installation. Here, I'll use pnpm:

pnpm add @mui/material @emotion/react @emotion/styled

After installation, let's test by adding a button to the page to see if everything is correct:

import Button from "@mui/material/Button";

export default function Home() {
  return (
    <>
      <div>Hello world</div>
      <br />
      <Button>CLick here</Button>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

If everything is installed properly, your browser will display it like this:

browser

Remember to start the Next.js server with pnpm dev.

Creating a Theme

Let’s create a theme.ts file in src/styles and set up a function to toggle the colors based on the chosen theme (light or dark):

import { PaletteMode } from "@mui/material";

const primaryDark = '#6a1b9a';
const primaryLight = '#4a148c';

export const getDesignTokens = (mode: PaletteMode) => ({
  palette: {
    mode,
    ...(mode === 'light'
      ? {
          primary: {
            main: primaryLight,
          },
        }
      : {
          // palette values for dark mode
          primary: {
            main: primaryDark,
          },
        })
  }
})
Enter fullscreen mode Exit fullscreen mode

For example, if we opt for the dark theme, we'll use the lighter purple since the background will already be dark, and vice versa.

Implementing Theme Switch

In layout.tsx, add the following imports:

...
import { PaletteMode } from '@mui/material'
import CssBaseline from '@mui/material/CssBaseline'
import { ThemeProvider, createTheme } from '@mui/material/styles'
...
Enter fullscreen mode Exit fullscreen mode

Set up a state to manage the theme and store it using useMemo:

const [mode, setMode] = useState<PaletteMode>('light')
const theme = useMemo(() => {
    return createTheme(getDesignTokens(mode))
}, [mode])
Enter fullscreen mode Exit fullscreen mode

Add the Material-UI provider to manage theme changes:

...
<html lang="en">
  <body className={inter.className}>
      <ThemeProvider theme={theme}>
      <CssBaseline />
      {children}
    </ThemeProvider>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Try toggling the state between light and dark:

Image browser
Image browser

Note: If you are using Next.js 14, include 'use client' at the beginning of the layout.tsx file.

Switching Themes with a Button

Create a button to easily switch the theme:

<Button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
  Toggle mode
</Button>
Enter fullscreen mode Exit fullscreen mode

And voilà! Your site is now ready to switch between two modes.

GIF Browser

Conclusion

Ideally, we should encapsulate all the theme logic in a provider to keep the layout clean and organized. This is just a simple example to kick-start your next project using Material-UI.

Got more tips? Questions or want to share another approach? Feel free to comment below!

Thanks for your attention, and see you next time!

GIT REPOSITORY

Top comments (0)