bestofreactjs.com Open in urlscan Pro
2606:4700:3032::ac43:883a  Public Scan

URL: https://bestofreactjs.com/repo/pacocoursey-next-themes-react-nextjs-extensions
Submission: On November 26 via manual from AU — Scanned from DE

Form analysis 1 forms found in the DOM

/search

<form class="d-sm-inline-block form-inline mr-auto my-2 my-md-0 mw-100 navbar-search" action="/search">
  <div class="input-group">
    <input type="text" class="form-control bg-white small" name="q" placeholder="Find Components..." aria-label="Search" aria-describedby="basic-addon2">
    <div class="input-group-append">
      <button class="btn btn-dark" type="submit">
        <i class="fa fa-search fa-sm"></i>
      </button>
    </div>
  </div>
</form>

Text Content

 * Audio / Video
 * Autocomplete
 * Awesome React Hooks
 * Boilerplate
 * Carousel
 * More Categories
   Charts Code Design Collapse Color Picker Communication with server Custom
   Scrollbar Data Managing Data Store Date / Time picker Development Tools Drag
   and Drop Events Form Logic Forms Graphics/Canvas i18n Icons Image
   manipulation Infinite Scroll Input Types Lazy Load Loader Spinners Progress
   Bars Maps Markdown Editor Material Design Menu Miscellaneous Mobile Next.js
   Apps Next.js Boilerplates Next.js Extensions Notification Overlay Paginator
   Photo / Image Props from server React Apps React Frameworks React Integration
   React Libraries React Native Animation React Native Apps React Native Awesome
   Components React Native Backend React Native Build & Development React Native
   Forms React Native Frameworks React Native Geolocation React Native
   Integrations React Native Media React Native Navigation React Native Seeds
   React Native Storage React Native System React Native Text & Rich Content
   React Native Utilities React Native Web React Performance React Renderers
   React Styling React Testing React UI Component Redux Tools Reporter Rich Text
   Editor Router Select Sortable List Star Rating Starter Kits and Toolchains
   Sticky Table Tabs Tag Input Templates Toggle Tooltip Tree UI Animation UI
   Frameworks UI Layout Utilities
 * Popular Components
 * Latest Components

 * Overview
 * Issues 5
 * Releases

 * Star 1.3k
 * Watch 9
 * Fork 38


PERFECT NEXT.JS DARK MODE IN 2 LINES OF CODE. SUPPORT SYSTEM PREFERENCE AND ANY
OTHER THEME WITH NO FLASHING

Paco
Last update: Nov 23, 2021


RELATED TAGS

Next.js Extensions react dark-theme nextjs themes dark-mode

OVERVIEW


NEXT-THEMES

An abstraction for themes in your Next.js app.

 * ✅ Perfect dark mode in 2 lines of code
 * ✅ System setting with prefers-color-scheme
 * ✅ Themed browser UI with color-scheme
 * ✅ No flash on load (both SSR and SSG)
 * ✅ Sync theme across tabs and windows
 * ✅ Disable flashing when changing themes
 * ✅ Force pages to specific themes
 * ✅ Class or data attribute selector
 * ✅ useTheme hook

Check out the Live Example to try it for yourself.


INSTALL

$ npm install next-themes
# or
$ yarn add next-themes


USE

You'll need a Custom App to use next-themes. The simplest _app looks like this:

// pages/_app.js

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

Adding dark mode support takes 2 lines of code:

import { ThemeProvider } from 'next-themes'

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider>
      <Component {...pageProps} />
    </ThemeProvider>
  )
}

export default MyApp

That's it, your Next.js app fully supports dark mode, including System
preference with prefers-color-scheme. The theme is also immediately synced
between tabs. By default, next-themes modifies the data-theme attribute on the
html element, which you can easily use to style your app:

:root {
  /* Your default theme */
  --background: white;
  --foreground: black;
}

[data-theme='dark'] {
  --background: black;
  --foreground: white;
}


USETHEME

Your UI will need to know the current theme and be able to change it. The
useTheme hook provides theme information:

import { useTheme } from 'next-themes'

const ThemeChanger = () => {
  const { theme, setTheme } = useTheme()

  return (
    <div>
      The current theme is: {theme}
      <button onClick={() => setTheme('light')}>Light Mode</button>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
    </div>
  )
}



> Warning! The above code is hydration unsafe and will throw a hydration
> mismatch warning when rendering with SSG or SSR. This is because we cannot
> know the theme on the server, so it will always be undefined until mounted on
> the client.
> 
> You should delay rendering any theme toggling UI until mounted on the client.
> See the example.


API

Let's dig into the details.


THEMEPROVIDER

All your theme configuration is passed to ThemeProvider.

 * storageKey = 'theme': Key used to store theme setting in localStorage
 * defaultTheme = 'system': Default theme name (for v0.0.12 and lower the
   default was light). If enableSystem is false, the default theme is light
 * forcedTheme: Forced theme name for the current page (does not modify saved
   theme settings)
 * enableSystem = true: Whether to switch between dark and light based on
   prefers-color-scheme
 * enableColorScheme = true: Whether to indicate to browsers which color scheme
   is used (dark or light) for built-in UI like inputs and buttons
 * disableTransitionOnChange = false: Optionally disable all CSS transitions
   when switching themes (example)
 * themes = ['light', 'dark']: List of theme names
 * attribute = 'data-theme': HTML attribute modified based on the active theme
   * accepts class and data-* (meaning any data attribute, data-mode,
     data-color, etc.) (example)
 * value: Optional mapping of theme name to attribute value
   * value is an object where key is the theme name and value is the attribute
     value (example)


USETHEME

useTheme takes no parameters, but returns:

 * theme: Active theme name
 * setTheme(name): Function to update the theme
 * forcedTheme: Forced page theme or falsy. If forcedTheme is set, you should
   disable any theme switching UI
 * resolvedTheme: If enableSystem is true and the active theme is "system", this
   returns whether the system preference resolved to "dark" or "light".
   Otherwise, identical to theme
 * systemTheme: If enableSystem is true, represents the System theme preference
   ("dark" or "light"), regardless what the active theme is
 * themes: The list of themes passed to ThemeProvider (with "system" appended,
   if enableSystem is true)

Not too bad, right? Let's see how to use these properties with examples:


EXAMPLES

The Live Example shows next-themes in action, with dark, light, system themes
and pages with forced themes.


USE SYSTEM PREFERENCE BY DEFAULT

The defaultTheme is "light". If you want to respect the System preference
instead, set it to "system":

">

<ThemeProvider defaultTheme="system">


IGNORE SYSTEM PREFERENCE

If you don't want a System theme, disable it via enableSystem:

<ThemeProvider enableSystem={false}>


CLASS INSTEAD OF DATA ATTRIBUTE

If your Next.js app uses a class to style the page based on the theme, change
the attribute prop to class:

">

<ThemeProvider attribute="class">

Now, setting the theme to "dark" will set class="dark" on the html element.


FORCE PAGE TO A THEME

Let's say your cool new marketing page is dark mode only. The page should always
use the dark theme, and changing the theme should have no effect. To force a
theme on your Next.js pages, simply set a variable on the page component:

// pages/awesome-page.js

const Page = () => { ... }
Page.theme = 'dark'
export default Page



In your _app, read the variable and pass it to ThemeProvider:



function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider forcedTheme={Component.theme || null}>
      <Component {...pageProps} />
    </ThemeProvider>
  )
}



Done! Your page is always dark theme (regardless of user preference), and
calling setTheme from useTheme is now a no-op. However, you should make sure to
disable any of your UI that would normally change the theme:

const { forcedTheme } = useTheme()

// Theme is forced, we shouldn't allow user to change the theme
const disabled = !!forcedTheme


DISABLE TRANSITIONS ON THEME CHANGE

I wrote about this technique here. We can forcefully disable all CSS transitions
before the theme is changed, and re-enable them immediately afterwards. This
ensures your UI with different transition durations won't feel inconsistent when
changing the theme.

To enable this behavior, pass the disableTransitionOnChange prop:

<ThemeProvider disableTransitionOnChange>


DIFFERING DOM ATTRIBUTE AND THEME NAME

The name of the active theme is used as both the localStorage value and the
value of the DOM attribute. If the theme name is "pink", localStorage will
contain theme=pink and the DOM will be data-theme="pink". You cannot modify the
localStorage value, but you can modify the DOM value.

If we want the DOM to instead render data-theme="my-pink-theme" when the theme
is "pink", pass the value prop:

<ThemeProvider value={{ pink: 'my-pink-theme' }}>

Done! To be extra clear, this affects only the DOM. Here's how all the values
will look:

"pink" document.documentElement.getAttribute('data-theme') // => "my-pink-theme"
">

const { theme } = useTheme()
// => "pink"

localStorage.getItem('theme')
// => "pink"

document.documentElement.getAttribute('data-theme')
// => "my-pink-theme"


MORE THAN LIGHT AND DARK MODE

next-themes is designed to support any number of themes! Simply pass a list of
themes:

<ThemeProvider themes={['pink', 'red', 'blue']}>

> Note! When you pass themes, the default set of themes ("light" and "dark") are
> overridden. Make sure you include those if you still want your light and dark
> themes:

<ThemeProvider themes={['pink', 'red', 'blue', 'light', 'dark']}>


WITHOUT CSS VARIABLES

This library does not rely on your theme styling using CSS variables. You can
hard-code the values in your CSS, and everything will work as expected (without
any flashing):

html,
body {
  color: #000;
  background: #fff;
}

[data-theme='dark'],
[data-theme='dark'] body {
  color: #fff;
  background: #000;
}


WITH STYLED COMPONENTS AND ANY CSS-IN-JS

Next Themes is completely CSS independent, it will work with any library. For
example, with Styled Components you just need to createGlobalStyle in your
custom App:

) } ">

// pages/_app.js
import { createGlobalStyle } from 'styled-components'
import { ThemeProvider } from 'next-themes'

// Your themeing variables
const GlobalStyle = createGlobalStyle`
  :root {
    --fg: #000;
    --bg: #fff;
  }

  [data-theme="dark"] {
    --fg: #fff;
    --bg: #000;
  }
`

function MyApp({ Component, pageProps }) {
  return (
    <>
      <GlobalStyle />
      <ThemeProvider>
        <Component {...pageProps} />
      </ThemeProvider>
    </>
  )
}


AVOID HYDRATION MISMATCH

Because we cannot know the theme on the server, many of the values returned from
useTheme will be undefined until mounted on the client. This means if you try to
render UI based on the current theme before mounting on the client, you will see
a hydration mismatch error.

The following code sample is unsafe:

import { useTheme } from 'next-themes'

const ThemeChanger = () => {
  const { theme, setTheme } = useTheme()

  return (
    <div>
      The current theme is: {theme}
      <button onClick={() => setTheme('light')}>Light Mode</button>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
    </div>
  )
}

To fix this, make sure you only render UI that uses the current theme when the
page is mounted on the client:



import { useTheme } from 'next-themes'

const ThemeChanger = () => {
  const [mounted, setMounted] = useState(false)
  const { theme, setTheme } = useTheme()

  // When mounted on client, now we can show the UI
  useEffect(() => setMounted(true), [])

  if (!mounted) return null

  return (
    <div>
      The current theme is: {theme}
      <button onClick={() => setTheme('light')}>Light Mode</button>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
    </div>
  )
}



To avoid Content Layout Shift, consider rendering a skeleton until mounted on
the client side.


WITH TAILWIND

Visit the live example • View the example source code

> NOTE! Tailwind only supports dark mode in version >2.

In your tailwind.config.js, set the dark mode property to class:

// tailwind.config.js
module.exports = {
  darkMode: 'class'
}



Set the attribute for your Theme Provider to class:

">

// pages/_app.js
<ThemeProvider attribute="class">

If you're using the value prop to specify different attribute values, make sure
your dark theme explicitly uses the "dark" value, as required by Tailwind.

That's it! Now you can use dark-mode specific classes:

">

<h1 className="text-black dark:text-white">


DISCUSSION


THE FLASH

ThemeProvider automatically injects a script into next/head to update the html
element with the correct attributes before the rest of your page loads. This
means the page will not flash under any circumstances, including forced themes,
system theme, multiple themes, and incognito. No noflash.js required.


FAQ

--------------------------------------------------------------------------------

Why is my page still flashing?

In Next.js dev mode, the page may still flash. When you build your app in
production mode, there will be no flashing.

--------------------------------------------------------------------------------

Why do I get server/client mismatch error?

When using useTheme, you will use see a hydration mismatch error when rendering
UI that relies on the current theme. This is because many of the values returned
by useTheme are undefined on the server, since we can't read localStorage until
mounting on the client. See the example for how to fix this error.

--------------------------------------------------------------------------------

Do I need to use CSS variables with this library?

Nope. See the example.

--------------------------------------------------------------------------------

Can I set the class or data attribute on the body or another element?

Nope. If you have a good reason for supporting this feature, please open an
issue.

--------------------------------------------------------------------------------

Can I use this package with Gatsby or CRA?

Nope.

--------------------------------------------------------------------------------

Is the injected script minified?

Yes, using Terser.

--------------------------------------------------------------------------------

Why is resolvedTheme necessary?

When supporting the System theme preference, you want to make sure that's
reflected in your UI. This means your buttons, selects, dropdowns, or whatever
you use to indicate the current theme should say "System" when the System theme
preference is active.

If we didn't distinguish between theme and resolvedTheme, the UI would show
"Dark" or "Light", when it should really be "System".

resolvedTheme is then useful for modifying behavior or styles at runtime:

const { resolvedTheme } = useTheme()

<div style={{ color: resolvedTheme === 'dark' ? white : black }}>

If we didn't have resolvedTheme and only used theme, you'd lose information
about the state of your UI (you would only know the theme is "system", and not
what it resolved to).

ISSUES

 * SYSTEM PREFERENCE DOESN'T WORK BY DEFAULT
   
   When I read the docs it looks like system preference is set to true by
   default.
   
   enableSystem = true: Whether to switch between dark and light based on
   prefers-color-scheme
   
   But when I implement this or just browse the demo
   https://next-themes-example.vercel.app/ or the one with Tailwind — even
   though my macOS preference is set to dark, the theme gets set to light.
   
   This doesn't look like a sane default or a bug. My thought process is that
   next-themes would by default prefer the system's preference when available
   and only fallback to light if it's not.
   
   Am I doing something wrong?
   
   question 
   opened by ahmadawais 16

 * RESOLVEDTHEME CAN BE `SYSTEM`
   
   I have noticed in testing that useTheme().resolvedTheme can be system. I
   think it's only happening in the first render, but I haven't tried making a
   minimal reproduction.
   
   I am using next-themes@npm:0.0.13-beta.2 [9e7cc] (via npm:beta [9e7cc]) and
   not passing any options to <ThemeProvider>.
   
   Is this expected behavior?
   
   bug 
   opened by jonahsnider 8

 * FEATURE/TESTING
   
   
   CHANGES REQUESTED IN ISSUE 12
   
   
   THIS PR INCLUDES THE FOLLOWING CHANGES:
   
    1. Setup for testing using Jest and @testing-library/react
    2. Test-suites for the following features:
       * different defaultThemes (4 test-cases)
       * using a custom storage-key (2 test-cases)
       * custom attribute (3 test-cases)
       * custom value-mapping (1 test-case)
   
   opened by trm217 6

 * HOW TO USE NEXT-THEMES WITH DESIGN LIBRARIES?
   
   In my latest project I used Ant Design as component framework and design
   library. But I still struggle to implement a dark mode switch in my NextJS
   app. Ant Design provides a dark mode and a compact mode by itself (in CSS and
   LESS) but as far as I can tell you would have to modify these files to use
   next-themes to toggle between those designs.
   
   Is there any better way to implement a theme switch but editing the provides
   style/creating a new one?
   
   opened by C0ntroller 5

 * DEFAULTTHEME NOT WORKING
   
   Im seeing two (related) issues with the library. Most obvious is that the
   defaultTheme doesn't appear to work.
   
   With a basic setup - system theme works great, but if I add the following,
   system theme is still active:
   
       <ThemeProvider defaultTheme="dark">
   
   
   I attempted to disable system theme which did turn off system theme but light
   theme remained.
   
   Further to the above - the repository example doesn't apply system theme when
   deployed to Vercel (although your demo does) - as can be seen in the public
   repository:
   
   https://next-themes.vercel.app/
   
   No default is set - but useTheme returns light instead of system.
   
   opened by glenarama 4

 * LICENSE MISSING
   
   Our legal team requires us to use packages after they review the license.
   Grateful if you can add something like that~
   
   opened by huysh3 4

 * NEXT-THEMES FAIL DURING INSTALLATION.
   
   When I run npm install next-themes, I am getting this error:
   
   npm ERR! Found: next@10.0.7
   npm ERR! node_modules/next
   npm ERR!   next@"10.0.7" from the root project
   npm ERR! 
   npm ERR! Could not resolve dependency:
   npm ERR! peer next@"^9.5.5" from next-themes@0.0.10
   npm ERR! node_modules/next-themes
   npm ERR!   next-themes@"0.0.10" from the root project
   
   
   Please advice. Thanks.
   
   opened by elnobun 4

 * INCORRECT BEHAVIOR WHEN USING PAYPAL BUTTONS
   
   
   EXPECTED BEHAVIOR
   
   The background of the component should be transparent. Paypal uses an iframe
   to display the buttons. I guess that's the problem. The library doesn't work
   with iframe correctly.
   
   
   CURRENT BEHAVIOR
   
   The background of the component is white. Regardless of which theme is
   selected or the which theme is forced.
   
   
   STEPS TO REPRODUCE
   
    1. Next JS Project
    2. Implement pay-pal buttons
    3. Implement next-themes package
    4. Load a page
   
   
   YOUR ENVIRONMENT
   
   | Syntax | Description | | ----------- | ----------- | | React | 17 | |
   Next-themes | 0.0.15 | | Next.js | 11 | | Paypal sdk | 4.1.0 | | Browser |
   93.0.4577.82 (Official Build) (x86_64) |
   
   opened by Pavelkovo 3

 * QUESTION: HOW DOES NEXT-THEMES RESOLVE "NO FLASH ON LOAD"?
   
   Or what part of the code do I need to read? I want to figure this out on my
   own. Let me know if you want to.
   
   opened by kimizuy 3

 * ADD TESTS
   
   We should use React Testing Library to setup tests for correct behavior,
   including:
   
    * Using attribute="class"
    * Using custom storageKey
    * Using custom value mappings
    * Using attribute="data-something-other-than-theme"
    * Using different defaultThemes
   
   enhancement help wanted 
   opened by pacocoursey 3

 * ADD `USECOLORMODE` FUNCTION THAT WAITS FOR MOUNT BEFORE RETURNING RESOLVED
   THEME
   
   Currently useTheme does not wait for react mount before returning the
   resolved theme
   
   This means that in the following example resolvedTheme will be different
   between server and client, which will cause the react rehydration mismatch
   error
   
   const theme = useTheme()
   return theme === 'dark' ? <DarkIcon/> : <LightIcon/>
   
   
   There could be another function that waits for react mount before changing
   the theme on client, to prevent these react errors, something like this
   
   export function useColorMode({ defaultTheme = 'light' } = {}) {
       const { resolvedTheme: _resolvedTheme, setTheme } = useNextTheme()
   
       const [resolvedTheme, setResolvedTheme] = useState(defaultTheme)
   
       // wait for mount before changing theme
       useEffect(() => {
           setResolvedTheme(_resolvedTheme)
       }, [_resolvedTheme])
   
       return {
           resolvedTheme,
           setTheme,
     
       }
   }
   
   
   I can make a PR if you agree
   
   opened by remorses 1

 * FEATURE REQUEST: SUPPORT FOR STORYBOOK
   
   Thanks for the library! It's very well rounded and more polished than what I
   was doing on my own.
   
   I'm looking to integrate this library with storybook for my application. When
   I was using my own theme provider example repo here which is heavily based on
   this blog post which provides the same solution this repo seeks to
   encapsulate in a library (i.e. inject script into head to run theme logic
   before first paint), I was able to easily integrate this with storybook
   globals. I went a step further to allow for stories to declare they want to
   be rendered with a certain theme by default with the following preview.js:
   
   import React, { useLayoutEffect } from 'react'
   import { usePrevious } from 'react-use'
   import { addons } from '@storybook/addons'
   import { UPDATE_GLOBALS } from '@storybook/core-events'
   import { ThemeContext, updateTheme } from 'components/Theme'
   
   export const globalTypes = {
     theme: {
       name: 'Theme',
       description: 'Color theme',
       defaultValue: 'light',
       toolbar: {
         icon: 'paintbrush',
         items: [
           { value: 'light', title: 'Light' },
           { value: 'dark', title: 'Dark' }
         ]
       }
     }
   }
   
   const updateThemeGlobal = theme =>
     addons.getChannel().emit(UPDATE_GLOBALS, {
       globals: { theme }
     })
   
   export const decorators = [
     (Story, { globals, parameters }) => {
       const previousParametersTheme = usePrevious(parameters.theme)
   
       useLayoutEffect(() => {
         if (
           previousParametersTheme !== parameters.theme &&
           globals.theme !== parameters.theme
         ) {
           updateThemeGlobal(parameters.theme)
         } else {
           updateTheme(globals.theme)
         }
       }, [globals.theme, parameters.theme])
   
       return (
         <ThemeContext.Provider
           value={{
             theme: globals.theme,
             setTheme: updateThemeGlobal
           }}
         >
           <Story />
         </ThemeContext.Provider>
       )
     }
   ]
   
   export const parameters = {
     theme: 'light'
   }
   
   
   I would like to accomplish something similar with this repo. i.e. allow
   outside code to force the theme and allow a custom version of the set theme
   function so we can keep the globals in sync.
   
   The context object isn't exported from this repo which would allow me to do
   all of this (alas, I would have to reimplement the logic to "set" the theme
   onto the dom unless that logic was also exported).
   
   I tried to get a partial solution by using the forceTheme prop on the
   provider as follows, but that didn't work either. It stayed on light mode
   even though the global was being reset causing a rerender.
   
     (Story, { globals }) => {
       return (
         <ThemeProvider
           forcedTheme={globals.theme}
           attribute="class"
           storageKey="themePreference"
         >
           <Story />
         </ThemeProvider>
       )
     }
   
   
   Is exporting the context object and dom update logic the best solution or is
   there a better way to achieve what I'm doing?
   
   Thanks for the help and your time; it's greatly appreciated.
   
   opened by RyanClementsHax 0

 * FEAT(LANG): ADD README PT-BR TRANSLATION
   
   Hey there,
   
   I added README.pt-br.me in the repository root and also fixed a minor error
   in the original file.
   
   opened by adryanrosa 0

 * ADD STITCHES EXAMPLE
   
   
   DESCRIPTION
   
   This PR adds an example on how to use next-themes with Stitches.
   
   opened by trm217 0

 * POSSIBILITY TO USE WITH CHAKRA-UI?
   
   Is it possible to use next-themes with Chakra? It seems next-themes is
   compatible with Tailwind, which is a relatively similar library to Chakra.
   Although Chakra has tried to prevent flashing, it is still widely occurring.
   I'm not sure how to incorporate next-themes with it since Chakra has its own
   dark/light toggle system.
   
   opened by SemperFortis 3

 * V0.0.16
   
   yarn add next-themes@beta
   
   
    * Fix the case where defaultTheme="dark", localStorage="light", and both the
      dark and light mode classes are added
    * Fix the case where entries in value are empty, like value={{ dark:
      'dark-mode' }} (missing light entry)
    * Set color-scheme in inline script instead of waiting for useEffect to
      batch global style recalculation
   
   opened by pacocoursey 0

 * IS THERE A WAY TO INITIALIZE THE THEME BY FETCHING THEME (ON THE SERVER SIDE)
   FROM A DATABASE?
   
   Thanks for the great library.
   
   My app has different themes that are stored in the user's account. How can I
   fetch the theme on the server side and then set the theme in next-themes? Or
   does this need to be set into local storage directly?
   
   opened by animeshchat 2

 * FIREFOX IS NOT SWITCHING BETWEEN LIGHT/DARK
   
   Hei,
   
   First of all i want to thank you about this lib ;) I have an issue with
   Firefox, even if the local storage is set and the class is added on <html>the
   theme does not change.
   
   I'm using the last next.js with tailwind jit
   
   opened by cmnstmntmn 11

 * ADD DOCUMENTATION FOR TESTING IMPLEMENTATIONS
   
   Hi, thanks for this library! It was so easy and fast to implement exactly
   what I needed! 🙌 Just wanted to share how I've started testing my
   implementations with React Testing Library:
   
   First, create a custom render function that includes the theme provider with
   an optional value:
   
   // test-utils.tsx
   import React, { ReactElement } from 'react';
   import { render, RenderOptions, RenderResult } from '@testing-library/react';
   import { ThemeProvider } from 'next-themes';
   
   interface TestProviderOptions {
     theme?: string;
   }
   
   interface CustomOptions extends RenderOptions, TestProviderOptions {}
   
   const createTestProviders = ({
     theme = 'dark',
   }: TestProviderOptions): React.FC => ({ children }) => (
     <ThemeProvider defaultTheme={theme} enableSystem={false} attribute="class">
       {children}
     </ThemeProvider>
   );
   
   const customRender = (
     ui: ReactElement,
     { theme, ...options }: CustomOptions = {},
   ): RenderResult =>
     render(ui, { wrapper: createTestProviders({ theme }), ...options });
   
   // re-export everything
   export * from '@testing-library/react';
   
   // override render method
   export { customRender as render };
   
   
   Second: Add a test-id to select your select (😁):
   
   // components/ThemeToggle.tsx
      <select
         className="font-semibold border border-gray-100 rounded"
         value={theme}
         data-testid="theme-select"
         onChange={handleChange}
       >
         <option value="light">Light Mode</option>
         <option value="dark">Dark Mode</option>
       </select>
   
   
   Third: Test that the toggle actually changes the theme. Of course the exact
   implementation here will differ depending on how you write your toggle.
   
   (technically you could assert the select value when you control it directly
   from the hook value, but I figured using a spy would be a bit more robust)
   
   // components/ThemeToggle.test.tsx
   import React from 'react';
   import { useTheme } from 'next-themes';
   import { render, fireEvent } from '../test/test-utils';
   import ThemeToggle from './ThemeToggle';
   
   const ThemeSpy: React.FC = () => {
     const { theme } = useTheme();
     return <span data-testid="theme-spy">{theme}</span>;
   };
   
   it('toggles the theme', async () => {
     const { getByTestId } = render(
       <>
         <ThemeToggle />
         <ThemeSpy />
       </>,
       { theme: 'dark' }, // Is also the default value, explicitly adding it here makes the test a bit more easy to read
     );
     const select = getByTestId('theme-select');
     const spy = getByTestId('theme-spy');
   
     fireEvent.change(select, { target: { value: 'light' } });
   
     expect(spy).toHaveTextContent('light');
   });
   
   
   Let me know if you see anything that could be improved of course! I think it
   would be nice to add this as an example for the next person. :)
   
   documentation 
   opened by GriffinSauce 1

 * IS USING WITH MATERIAL UI OR SIMILAR POSSIBLE?
   
   I had a comment about asking to solve this issue @mui-org before:
   https://github.com/mui-org/material-ui/issues/12827#issuecomment-649595621
   
   But just to be clear, there is probably no workaround to get this work with
   Material UI and similar libraries without them being able to read CSS
   variables, right?
   
   question 
   opened by balazsorban44 14

OWNER

PACO

Design & Code
GitHub Repository https://next-themes-example.vercel.app/

NEXT.JS PLUGIN TO TRANSPILE CODE FROM NODE_MODULES

Next.js + Transpile node_modules Transpile modules from node_modules using the
Next.js Babel configuration. Makes it easy to have local libraries and

771 Nov 22, 2021

EXTENDED NEXT.JS SERVER WITH PKG SUPPORT

Next-Pkg is a package for compiling your Next.js project with pkg. This is how
you can deploy your Next.js apps on enviroments without node installed!

55 Aug 30, 2021

NEXT SEO IS A PLUG IN THAT MAKES MANAGING YOUR SEO EASIER IN NEXT.JS PROJECTS.

Next SEO Next SEO is a plugin that makes managing your SEO easier in Next.js
projects. Pull requests are very welcome. Also make sure to check out the

4k Nov 21, 2021

NEXT-USERAGENT PARSES BROWSER USER-AGENT STRINGS FOR NEXT.JS

next-useragent ⚠️ Version 2 of this library will work only with Next.js 9. If
you're using Next.js 6-8 you can use previous versions. ⚠️ next-useragen

265 Nov 9, 2021

REACT AND NEXT.JS SITE TO DISPLAY DISCORD SERVER EXPERIMENTS AND THEIR ROLLOUTS

Discord Server Experiment Rollouts https://rollouts.advaith.io This is a site
made with React and Next.js to display the current Discord server experi

12 Oct 2, 2021

NEXT PLUGIN FOR .GRAPHQL AND .GQL FILES USING GRAPHQL-TAG

Next.js + Graphql Use Graphql files with Next.js Installation npm install
next-plugin-graphql or yarn add next-plugin-graphql Usage Create a next.conf

52 Nov 17, 2021

COOKIE SERIALIZER AND DESERIALIZER LIBRARY FOR NEXT.JS

next-cookie Cookie serializer and deserializer library for next.js. Installation
$ npm install next-cookie Usage HOCs The cookies are read and write

160 Nov 18, 2021

SIMPLE PROMISE-BASED SESSION MIDDLEWARE FOR NEXT.JS, MICRO, EXPRESS, AND MORE

next-session Simple promise-based session middleware for Next.js. Also works in
micro or Node.js HTTP Server, Express, and more. Project status: While

217 Nov 24, 2021

🛠 NEXT.JS STATELESS SESSION UTILITY USING SIGNED AND ENCRYPTED COOKIES TO STORE
DATA

next-iron-session ?? Next.js and Express (connect middleware) stateless session
utility using signed and encrypted cookies to store data This Next.js,

1k Nov 18, 2021

THE TYPESCRIPT-READY, MINIMAL ROUTER AND MIDDLEWARE LAYER FOR NEXT.JS, MICRO,
VERCEL, OR NODE.JS HTTP/HTTP2

next-connect The smol method routing and middleware for Next.js (also works in
other frameworks). Powered by trouter. Features Compatible with Express

846 Nov 25, 2021

EFFORTLESS DEPLOYMENT TO AWS AND GITHUB PAGES FOR NEXT.JS APPS 🚀

Next Deploy Effortless deployment to AWS and GitHub Pages for Next.js apps ??
Table of Contents Getting Started Features Background CLI Distributed De

39 Sep 16, 2021

LANGUAGE DETECTOR THAT WORKS UNIVERSALLY (BROWSER + SERVER) - MEANT TO BE USED
WITH A UNIVERSAL FRAMEWORK, SUCH AS NEXT.JS

Universal Language Detector Language detector that works universally (browser +
server) On the server, will rely on "cookies > accept-language header"

63 Nov 17, 2021

UNIVERSAL DYNAMIC ROUTES FOR NEXT.JS

Dynamic Routes for Next.js Easy to use universal dynamic routes for Next.js
Express-style route and parameters matching Request handler middleware for

2.4k Nov 17, 2021

APOLLO HOC FOR NEXT.JS

next-with-apollo Apollo HOC for Next.js. For Next v9 use the latest version. For
Next v6-v8 use the version 3.4.0. For Next v5 and lower go here and u

746 Nov 15, 2021

A STATIC SITE GENERATOR WITH MARKDOWN + REACT FOR NEXT.JS

nextein A static site generator based in Next.js Site | Documentation | Guides
What is it? nextein is a wrapper around next.js that allows you to writ

848 Nov 17, 2021

⚡ DEPLOY YOUR NEXT.JS APPS ON AWS LAMBDA@EDGE VIA SERVERLESS COMPONENTS

Serverless Next.js Component A zero configuration Next.js 9.0 serverless
component for AWS Lambda@Edge aiming for full feature parity. Please review f

2.9k Nov 24, 2021

ZERO CONFIG PWA PLUGIN FOR NEXT.JS, WITH WORKBOX 🧰

Zero Config PWA Plugin for Next.js This plugin is powered by workbox and other
good stuff. Features 0️⃣ Zero config for registering and generating a s

1.8k Nov 24, 2021

A NEXT.JS PLUGIN FOR EMBEDDING OPTIMIZED IMAGES.

Next.js plugin for embedding optimized images. Features import png/jpg images
output to webp format resize to multiple screen sizes and densities opti

180 Nov 12, 2021

AUTHENTICATION FOR NEXT.JS

NextAuth.js Authentication for Next.js Open Source. Full Stack. Own Your Data.
Overview NextAuth.js is a complete open source authentication solution

8.1k Nov 25, 2021

Copyright © 2021.BestofReactjs All rights reserved.

 * 
 * 
 * 
 * 
 *