Git Product home page Git Product logo

next-themes's People

Contributors

0xflotus avatar amrhassab avatar bekzodisakov avatar blankparticle avatar brunocrosier avatar claytonfaria avatar davidwells avatar dimamachina avatar gnoff avatar hahlh avatar innei avatar kosai106 avatar mattboon avatar mondoadams avatar pacocoursey avatar phuctm97 avatar styfle avatar trenaryja avatar trm217 avatar unsleeping avatar wits avatar yurtaev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

next-themes's Issues

White border around messenger's customer chat icon on dark mode after reload a website

Hello, I got a dark mode from next/themes and on dark mode on my smartphone there is a white border of the messenger's icon (react-messenger-customer-chat). When I enter the website, change the theme to dark and then again enter the website there is white border around messenger's the icon and white bubble for the notifications. How to apply a color to this iframe and bubble for notifications? It doesn't look good ;/. I use tailwindcss and next.js.

image

I tried like this but dont work.:

@layer components {
  .cms-content > h1,
  h2 {
    @apply dark:text-gray-600;
  }
  .messenger-chat-bubble > iframe {
    @apply dark:bg-dark-posts;
  }
}

app.js

import "tailwindcss/tailwind.css";
import "../styles/globals.css";
import Footer from "../components/Footer";
import Header from "../components/Header";
import { getMDXComponent } from "mdx-bundler/client";
import MessengerCustomerChat from "react-messenger-customer-chat";

import { ThemeProvider } from "next-themes";

function MyApp({ Component, pageProps }) {
  return (
    <>
      <ThemeProvider attribute="class">
        <Header />
        <Component {...pageProps} />

        <Footer />
        {typeof window !== "undefiend" && (
          <MessengerCustomerChat
            pageId="1xxxxx"
            appId="xxx"
            className="messenger-chat-bubble"
          />
        )}
      </ThemeProvider>
    </>
  );
}
export default MyApp;

After entering the website, changing the theme to dark and reload the page
200619910_970589787109373_1985134886635526940_n

I tried this but didn't help

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .cms-content > h1,
  h2 {
    @apply dark:text-gray-600;
  }
  .messenger-chat-bubble > iframe {
    @apply dark:bg-dark-posts;
  }
  .messenger-chat-bubble > .fb_customer_chat_icon {
    @apply dark:bg-dark-posts;
  }
}

data-theme & class at the same time?

I'd like to use attribute class and data-theme. How can I realise that?

In my case, I'm trying to combine my own css files with tailwind css. However, when I put attribute to class, none of my css aren't working, whilst tailwind itself doesn't on data-theme!

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

Using theme to dynamically show Stripe Elements Styles

Hello,

I am using stripe elements and dynamically changing the input styles depending on the theme. It works, but my only problem is if I change the theme whilst being on the page containing the the stripe elements input I have to hard refresh the page in order to see the css changes.

What I am trying to achieve is is to get the styles to change when the theme changes. Please note, I am trying to change the backgroundColor.

Here's what I currently have:

import { useTheme } from "next-themes";

 const { resolvedTheme, setTheme } = useTheme();

  const CARD_OPTIONS = {
    iconStyle: "solid",
    style: {
      base: {
        backgroundColor: `${resolvedTheme === "dark" ? "black" : "white"}`,
        iconColor: "#6D28D9",
        color: `${resolvedTheme === "dark" ? "white" : "#9CA3AF"}`,
        fontWeight: "500",
        fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
        fontSize: "16px",
        fontSmoothing: "antialiased",
        ":-webkit-autofill": {
          color: "#fce883",
        },
        "::placeholder": {
          color: "#D1D5DB",
        },
      },
      invalid: {
        iconColor: "#ef2961",
        color: "#ef2961",
      },
    },
  };

<CardElement options={CARD_OPTIONS} />

Another option I have tried is using mount and then passing DARK_CARD_OPTIONS to the Card Element.

Like so:

const [mounted, setMounted] = useState(false);

useEffect(() => setMounted(true), []);

 const DARK_CARD_OPTIONS = {
    iconStyle: "solid",
    style: {
      base: {
        backgroundColor: "red",
        iconColor: "#6D28D9",
        color: "white",
        fontWeight: "500",
        fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
        fontSize: "16px",
        fontSmoothing: "antialiased",
        ":-webkit-autofill": {
          color: "#fce883",
        },
        "::placeholder": {
          color: "#D1D5DB",
        },
      },
      invalid: {
        iconColor: "#ef2961",
        color: "#ef2961",
      },
    },
  };

  {mounted && (
          <div className="p-4 rounded-lg border border-gray-800 dark:border-gray-600 focus:border-purple-700">
            {resolvedTheme === "dark" ? (
              <CardElement options={DARK_CARD_OPTIONS} />
            ) : (
              <CardElement options={CARD_OPTIONS} />
            )}
          </div>
        )}

For some reason this only makes some areas of the CardElements input change dynamically.

Please see screen shot below (please note I've used red to make it stand out):

Screen Shot 2021-12-21 at 8 25 27 am

Screen Shot 2021-12-21 at 8 35 10 am

Auto-set light theme in print mode?

My resume looks great in dark theme and light theme, but when printing in dark theme, the browser removes the background but I'm left with the text showing as bad contrast since the site thinks it's still in dark mode.

Is there a good way to better support printing themes?

Question

Hi, can we set other HTML elements other than the "background" or "colour". Try to set border-colour for each theme but it's not working.

Add theme hints for modern browsers

Modern browsers can use this hint to render better scrollbars, inputs, etc. it could be done from css

:root {
  color-scheme: dark;   /* dark | light */
}

My workaround is including this somewhere

const { resolvedTheme } = useTheme();
useEffect(() => {
  if (typeof window != 'undefined') {
    document.documentElement.style.setProperty('color-scheme', resolvedTheme || 'light');
  }
}, [resolvedTheme]);

Add types

No reason not to have them โ€“ skipped it for the initial release because I was iterating quickly.

Cookie Strategy

I was performance testing a website using next-themes and I noticed that it seemed to delay the first paint a little bit. Would you be open to using a cookie-based strategy that would allow for reading the user-set theme directly on the server-side rather than having to define a script tag that is inserted into the head of the document?

next-themes fail during installation.

When I run npm install next-themes, I am getting this error:

npm ERR! Found: [email protected]
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 [email protected]
npm ERR! node_modules/next-themes
npm ERR!   next-themes@"0.0.10" from the root project

Please advice. Thanks.

Next 11 compatibility and flashing issues

It seems that this package doesn't work with nextjs 11.

Bug

I'm doing SSG with next 11.1.2 and gh-pages, but the theme is still flashing. For example, if you have a dark theme on the OS level, and you set the website to be light, you will see the dark one flashing before loading the light one and applying the data attribute.

Cause

I've checked other websites using this packages, and they are all using next 10. Also, maybe this can be the issue here, the script tag inside head is generated with a wrong and hashed type on next 11, this doesn't occur with next 10.

This is the screen viewing the page source.
Screenshot 2021-09-28 at 08 17 48

Another issue is that this package still puts scripts inside Head, while on next 11 we should use the Script component

Live

https://design.wonderflow.ai/

Repository

https://github.com/wonderflow-bv/design

Inject script to pass CSP security header

Currently, when using this package and having a restrictive CSP header (including a hash), you get the following error:

Refused to execute inline script because it violates the following Content Security Policy directive:
"script-src 'self' 'sha256-8vI1As+YvGPUUpPp6RL6G2wI9FGjUN3x9MU3jdupP4s='". Either the 'unsafe-inline' keyword,
a hash ('sha256-ZxiMCbcVxDCutNT7QrHdr+d0Z99vF3DED6pLitElTag='), or a nonce ('nonce-...')
is required to enable inline execution.

As the error says, including a nonce in the script header here would fix the error most likely. An optional parameter passed down from the ThemeProvider.

Option to use sessionStorage instead of localStorage

Hello! I noticed after adding this to my project that because it uses localStorage, the theme always persists between sessions.

When someone visits my site, I'd prefer to have it get the default theme first (i.e. system), if for example the system theme has changed from their previous session because they're visiting at a different time of day.

I've implemented this in #71. Please let me know what you think!

Support themed SSG

Hi,
I haven't had the chance to test this library but I've checked the README quickly. It seems you cannot yet support themed SSG.
I've been working on this subject a lot last year, and the introduction of Middlewares finally provided a solution to this.

The use case is very similar to A/B testing, see https://github.com/vercel/examples/tree/main/edge-functions/ab-testing-simple

To sum it up:

  • You store the current theme as a cookie, so it is sent to the server with each request
  • You add a route parameter "[theme]", so basically a folder named [theme] at the root of your pages folder
  • You add a middleware that rewrites any route "/my-route" => "selected-theme/my-route". Rewrite do not alter the URL so it's fine to add a new param like this
  • You use getStaticPaths so that you can render 2 variations for each page

I've written an article to show how it scales to even more parameters: https://blog.vulcanjs.org/render-anything-statically-with-next-js-and-the-megaparam-4039e66ffde. You can skip to the code demo, I show theming and multi-tenancy: https://github.com/VulcanJS/vulcan-next/blob/devel/src/pages/vn/examples/%5BM%5D/megaparam-demo.tsx
I call this a "hidden param trick" or "Megaparam".

Hope you'll enjoy!

Theme switch not working if started from a forced theme page

Hi, loving this library! Just found a bug here and wondering if there's a fix!

Problem
When started from a forced theme page, and then navigated back to a normal page, the dark/light switch doesn't work

Steps to Reproduce

  1. In a new tab to https://next-themes-example.vercel.app/dark
  2. Press "Go back home"
  3. Switch from Light to Dark mode -> this doesn't work

Tested on Chrome/MacOS and Firefox/MacOS

Screen.Recording.2021-06-11.at.2.31.19.PM.mov

Thank you!!

EnableSystem does not seem to work

As a user who has "dark" mode enabled on their system, but wants to make an app that completely ignores system theme, I ran into the following issue:

// _app.tsx

  <ThemeProvider
      attribute="class"
       defaultTheme="light"
      enableSystem={false}
    >
    {...etc}
    </ThemeProvider>

yields the following:

<html class="system dark">
...etc
</html>

Getting a warning: There are multiple modules with names that only differ in casing.

Hi, thanks to your library, my learning to add theme switcher in nextjs looks good :)
I would like to ask one thing that's appearing in the console: There are multiple modules with names that only differ in casing.

Is there a way to resolve it?

My _app.js. I've used ThemeProvider but the warning remains.

import Head from 'next/Head'
import '../styles/globals.css'
import { ThemeProvider as NextThemeProvider } from 'next-themes'

function MyApp ({ Component, pageProps }) {
  return (
    <>
      <Head>
        <title>My Blog</title>
      </Head>
      <NextThemeProvider attribute='class' defaultTheme='system'>
        <Component {...pageProps} />
      </NextThemeProvider>
    </>
  )
}

export default MyApp

The warning:

./node_modules/next/Head.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* /Users/m/Code/playground/next/myblog/node_modules/next/Head.js
    Used by 1 module(s), i. e.
    /Users/m/Code/playground/next/myblog/node_modules/@next/react-refresh-utils/loader.js!/Users/m/Code/playground/next/myblog/node_modules/next/dist/build/webpack/loaders/next-babel-loader.js??ruleSet[1].rules[1].use[1]!/Users/m/Code/playground/next/myblog/pages/_app.js
* /Users/m/Code/playground/next/myblog/node_modules/next/head.js
    Used by 1 module(s), i. e.
    /Users/m/Code/playground/next/myblog/node_modules/next-themes/dist/index.modern.js

package.json

{
  "name": "myblog",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@headlessui/react": "^1.0.0",
    "@heroicons/react": "^1.0.1",
    "next": "10.1.3",
    "next-themes": "^0.0.14",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "styled-components": "^5.2.3",
    "twin.macro": "^2.3.3"
  },
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "babel-plugin-macros": "^3.0.1",
    "postcss": "^8.2.10",
    "tailwindcss": "^2.1.1"
  },
  "babelMacros": {
    "twin": {
      "preset": "styled-components"
    }
  }
}

Can I apply multiple themes?

Hello, Thanks for the nice library.

I want to use this library to apply multiple themes of different nature.
In the example below, I am trying to apply a cross between two different color themes and two different font themes.

The current method applies all CSS variables to each theme:

:root {
  /* default theme (light small) */
  --background: white;
  --foreground: black;
  --fontsize: 16px;
}

:[data-theme='light large'] {
  --background: white;
  --foreground: black;
  --fontsize: 32px;
}

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

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

However, with this method, the amount of description increases in proportion to the number of themes as the number of CSS properties increases.
My goal is to compose CSS using only the properties of each theme.

Like so:

:root {
  /* default theme (light small) */
  --background: white;
  --foreground: black;
  --fontsize: 16px;
}

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

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

[data-theme*='small'] {
  --fontsize: 16px;
}

[data-theme*='large'] {
  --fontsize: 32px;
}

Are there any good methods for that?
Pardon my broken English.

Temporarily changing the theme for certain pages

Hi there, firstly, I love this project and thanks for working on it!

We have a few custom landing pages where the theme is dark. I was wondering if there was an option (or a way) to temporarily set the theme just for that page and not store the the new theme in localStorage. That way when the user visits another page, it doesn't carry across the theme.

Thanks

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?

Warning: Text content did not match. Server: "sun" Client: "moon"

My code working well but I see a warning in console.

Warning: Text content did not match. Server: "sun" Client: "moon"

import { useTheme } from "next-themes";

const ThemeSwitcher = () => {
  const { theme, setTheme } = useTheme();

  const themeIcon = theme === "light" ? "moon" : "sun"; // because of this code
  const changeTheme = () => {
    return theme === "light" ? setTheme("dark") : setTheme("light");
  };
  return (
    <div onClick={changeTheme}>
      {themeIcon}
    </div>
  );
};

export default ThemeSwitcher;

How can I fix this?

Wrong theme if try to set "system" theme twice

What

  1. Setup ThemeProvider and useTheme with all default props
  2. Have a button that calls setTheme("system")
  3. Click on the button once -> it works correctly, HTML's data-theme is the correct theme (either "light" or "dark")
  4. Click again on that button -> it works incorrectly, HTML's data-theme is "system"

Why

Current source: https://github.com/pacocoursey/next-themes/blob/7c8a3269ca46f2accad778f04820075134bc6c50/index.tsx

In the 1st click of the button:

  1. When "setTheme" is called, "changeTheme" is always called
  2. In "changeTheme", the data-theme attribute is set to the chosen theme, which is "system"
  3. The "handleMediaQuery" effect is triggered due to "theme" changed, which set data-theme to the correct value (either "light" or "dark")

In the 2nd click of the button: step 1 and 2 are the same with the 1st click, but since the theme value (in state) is not changed (still "system"), the "handleMediaQuery" is not triggered, and thus the data-theme is not changed and is still "system" as in the 2nd step.

I reviewed the 0.13 PR and it seems this still happens

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

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.

Use <Script beforeInteractive /> instead of next/head for no flash injection?

To my understanding next/head (not to be confused with {Head} from 'next/document') loads during client runtime as it allows users to dynamically update <title> etc...

I think Nextjs's Script tab with the beforeInteractive prop set is more suitable for this use-case
https://nextjs.org/docs/basic-features/script

beforeInteractive
Scripts that load with the beforeInteractive strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy should be used for any critical scripts that need to be fetched and executed before the page is interactive.

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?

`resolvedTheme` always returns `undefined`. `theme` does the same.

I was trying out next-themes for the last couple of weeks. I had a Mac then & I got it to work. Suddenly, it stopped working.

I thought @mdx-js/loader was the issue so I switched to mdx-bundler. Now on my Windows PC, it still returns undefined.

Idk what's the issue? Looks like everything I'm doing is right as per the docs.

I have made a complete repro that doesn't work https://github.com/deadcoder0904/mdx-bundler-next-themes-error

I have added ThemeProvider:

https://github.com/deadcoder0904/mdx-bundler-next-themes-error/blob/6c430e99caf932b2c96064449d3a3711df023ee8/src/pages/_app.tsx#L23-L25

And toggle the themes perfectly:

https://github.com/deadcoder0904/mdx-bundler-next-themes-error/blob/6c430e99caf932b2c96064449d3a3711df023ee8/src/components/DarkMode.tsx#L17

Yet I still get the undefined error. Is there something I am doing wrong?

Server / client mismatch

When using the useTheme hook I'm getting an error when trying to read the theme value. Using Next v10.

import { useTheme } from "next-themes"

export default function ThemeChanger() {
    const { theme, setTheme } = useTheme()

    return (
        <div>
	    <div>{theme}</div>
	    <button onClick={() => setTheme("light")}>Light Mode</button>
	    <button onClick={() => setTheme("dark")}>Dark Mode</button>
        </div>
    )
}

Warning: Text content did not match. Server: "" Client: "dark"

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

License Missing

Our legal team requires us to use packages after they review the license.
Grateful if you can add something like that~

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.

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.
Screenshot 2021-11-01 at 23 34 34

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)

Change only being done once

I'm currently using tailwindcss with my project and I have set it up to use next-themes.

I currently have a button that calls a function that sets the theme.

const toggleLight = () => { setTheme(theme === "light" ? "dark" : "light"); };

But when I call this function it works and then if I try to call it a second time it doesn't change the theme.

enmqjQuINE.mp4

@import based on theme?

I have two themes in seperate stylesheets, and I was wondering if it's possible to import them based on the current theme. So it would import the dark.css if it's set to dark theme, or light.css if it's set to light theme.

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.

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. :)

Implementing with Persistent Layouts

Hello,

I love this, thank you.

I'm using the Next layout component example: https://github.com/vercel/next.js/tree/canary/examples/layout-component which alters the _app.js file like so:

function MyApp({ Component, pageProps }) { const getLayout = Component.getLayout || ((page) => page) return getLayout ( <Component {...pageProps} /> ) }

This breaks next-themes if we wrap the in a . Any change theme buttons do nothing at all. Is there a way to get them both to work together, please?

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?

Add finalTheme

I would like to see a new attribute from useTheme called something like finalTheme which merges forcedTheme and resolvedTheme. This would be helpful so each project doesn't have to do it separately.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.