Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Implementing a Custom Dark Mode Hook in Next.js
Sanon Joas
Sanon Joas

Posted on

Implementing a Custom Dark Mode Hook in Next.js

Dark mode has become an essential feature in modern web applications. In this tutorial, we'll create a custom dark mode hook for Next.js using TypeScript, which supports system preferences and allows manual override.

Prerequisites

  • Basic knowledge of React and Next.js
  • Node.js installed on your machine
  • A Next.js project set up with TypeScript

Step 1: Create the Dark Mode Hook

First, let's create our custom dark mode hook. Create a new fileuseDarkMode.ts in your project'shooks folder:

// hooks/useDarkMode.tsimport{useState,useEffect,useCallback}from'react'typeMode='light'|'dark'|'system'exportconstuseDarkMode=()=>{const[mode,setMode]=useState<Mode>('system')constapplyTheme=useCallback((isDark:boolean)=>{document.documentElement.classList.toggle('dark',isDark)},[])constchangeMode=useCallback((newMode:Mode)=>{setMode(newMode)localStorage.setItem('theme',newMode)},[])useEffect(()=>{constsavedTheme=localStorage.getItem('theme')asMode|nullif(savedTheme){setMode(savedTheme)}constmediaQuery=window.matchMedia('(prefers-color-scheme: dark)')consthandleSystemThemeChange=(event:MediaQueryListEvent)=>{if(mode==='system'){applyTheme(event.matches)}}constapplyCurrentTheme=()=>{if(mode==='system'){applyTheme(mediaQuery.matches)}else{applyTheme(mode==='dark')}}applyCurrentTheme()mediaQuery.addEventListener('change',handleSystemThemeChange)return()=>{mediaQuery.removeEventListener('change',handleSystemThemeChange)}},[mode,applyTheme])return{mode,changeMode}}
Enter fullscreen modeExit fullscreen mode

This hook manages the dark mode state, applies the theme to the document, and listens for system preference changes.

Step 2: Create a Dark Mode Provider

Now, let's create a provider component to wrap our app. Create a new fileDarkModeProvider.tsx in your project'scomponents folder:

// components/DarkModeProvider.tsximportReact,{createContext,useContext}from'react'import{useDarkMode}from'../hooks/useDarkMode'typeDarkModeContextType=ReturnType<typeofuseDarkMode>constDarkModeContext=createContext<DarkModeContextType|undefined>(undefined)exportconstDarkModeProvider:React.FC<{children:React.ReactNode}>=({children})=>{constdarkMode=useDarkMode()return(<DarkModeContext.Providervalue={darkMode}>{children}</DarkModeContext.Provider>)}exportconstuseDarkModeContext=()=>{constcontext=useContext(DarkModeContext)if(context===undefined){thrownewError('useDarkModeContext must be used within a DarkModeProvider')}returncontext}
Enter fullscreen modeExit fullscreen mode

This provider component will make our dark mode functionality available throughout the app.

Step 3: Wrap Your App with the Dark Mode Provider

Update yourpages/_app.tsx file to use the DarkModeProvider:

// pages/_app.tsximporttype{AppProps}from'next/app'import{DarkModeProvider}from'../components/DarkModeProvider'import'../styles/globals.css'functionMyApp({Component,pageProps}:AppProps){return(<DarkModeProvider><Component{...pageProps}/></DarkModeProvider>)}exportdefaultMyApp
Enter fullscreen modeExit fullscreen mode

Step 4: Create a Theme Toggle Component

Create a new component for the theme toggle button. Create a fileThemeToggle.tsx in yourcomponents folder:

// components/ThemeToggle.tsximportReactfrom'react'import{useDarkModeContext}from'./DarkModeProvider'constThemeToggle:React.FC=()=>{const{mode,changeMode}=useDarkModeContext()return(<selectvalue={mode}onChange={(e)=>changeMode(e.target.valueas'light'|'dark'|'system')}className="p-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-800 dark:text-white"><optionvalue="light">Light</option><optionvalue="dark">Dark</option><optionvalue="system">System</option></select>)}exportdefaultThemeToggle
Enter fullscreen modeExit fullscreen mode

Step 5: Add CSS for Light and Dark Themes

Update yourstyles/globals.css file to include styles for both light and dark themes:

/* styles/globals.css */@tailwindbase;@tailwindcomponents;@tailwindutilities;:root{--foreground-rgb:0,0,0;--background-start-rgb:214,219,220;--background-end-rgb:255,255,255;}.dark{--foreground-rgb:255,255,255;--background-start-rgb:0,0,0;--background-end-rgb:0,0,0;}body{color:rgb(var(--foreground-rgb));background:linear-gradient(tobottom,transparent,rgb(var(--background-end-rgb)))rgb(var(--background-start-rgb));}
Enter fullscreen modeExit fullscreen mode

Step 6: Use the Theme in Your Components

Now you can use the theme in your components. Update yourpages/index.tsx:

// pages/index.tsximportHeadfrom'next/head'importThemeTogglefrom'../components/ThemeToggle'exportdefaultfunctionHome(){return(<divclassName="min-h-screen p-4"><Head><title>DarkModeDemo</title><linkrel="icon"href="/favicon.ico"/></Head><mainclassName="max-w-4xl mx-auto"><h1className="text-4xl font-bold mb-4">WelcometoDarkModeDemo</h1><ThemeToggle/><pclassName="mt-4">Thisissomesampletexttoshowthethemechange.</p></main></div>)}
Enter fullscreen modeExit fullscreen mode

Step 7: Configure Tailwind for Dark Mode

Update yourtailwind.config.js to enable the 'class' strategy for dark mode:

// tailwind.config.jsmodule.exports={darkMode:'class',// ... rest of your config}
Enter fullscreen modeExit fullscreen mode

Step 8: Test Your Dark Mode

Run your Next.js application:

npm run dev
Enter fullscreen modeExit fullscreen mode

Visithttp://localhost:3000 in your browser. You should now see your application with a working dark mode toggle that respects system preferences and allows manual override!

Conclusion

Congratulations! You've successfully implemented a custom dark mode hook in your Next.js application. This implementation uses React hooks for state management, respects system preferences, allows manual override, and uses Tailwind CSS for styling.

Remember to consider accessibility when implementing dark mode, ensuring that there's sufficient contrast between text and background colors in both themes.

Happy coding!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

quinon proficit deficit...
  • Location
    Port-au-Prince
  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp