Felipe Saldanha
Felipe Saldanha

Reputation: 1365

How to make dark mode of Tailwind CSS work with Next.js and styled-jsx?

My site is built with Next.js and Tailwind CSS. I followed the default instructions to install them. Since I wanted to customize the appearance of my links without applying inline classes to each one, I also installed styled-jsx-plugin-postcss so that I could use styled-jsx already bundled in Next.js.

It worked almost perfectly, but for some reason the dark mode styles applied in the <style jsx> tag are ignored. I'm using the class strategy as documented. How can I make these styles work?

Below is a sample code from index.js. I also uploaded it to Codesandbox.

import { useState, useEffect } from "react";

export default function IndexPage() {
  const [mounted, setMounted] = useState(false);

  const handleThemeChange = (newTheme) => {
    const bodyClasses = document.body.classList;
    newTheme === "dark" ? bodyClasses.add("dark") : bodyClasses.remove("dark");
    localStorage.theme = newTheme;
  };

  useEffect(() => {
    const defaultTheme =
      localStorage.theme ||
      (window.matchMedia("(prefers-color-scheme: dark)").matches
        ? "dark"
        : "light");
    handleThemeChange(defaultTheme);
    setMounted(true);
  }, []);

  if (!mounted) return null;

  return (
    <div className="dark:bg-black dark:text-white text-xl">
      <ul className="cursor-pointer mb-6">
        <li
          onClick={() => handleThemeChange("dark")}
          className="block dark:hidden"
        >
          Click to activate dark mode
        </li>
        <li
          onClick={() => handleThemeChange("light")}
          className="hidden dark:block"
        >
          Click to activate light mode
        </li>
      </ul>
      <p>
        <a href="#">This link</a> should be red in dark mode.
      </p>
      <style jsx>{`
        a {
          @apply text-green-500 dark:text-red-500;
        }
      `}</style>
    </div>
  );
}

Upvotes: 1

Views: 835

Answers (1)

Felipe Saldanha
Felipe Saldanha

Reputation: 1365

After some digging, I realized that when the dark: variant is used inside <style jsx>, the .dark class generated in the final CSS is also scoped. So I have to do a workaround using the one-off global selector :global():

<style jsx>{`
  a {
    @apply text-green-500;
  }

  :global(.dark) a {
    @apply text-red-500;
  }
`}</style>

It demands slight code refactoring, but I'm afraid there's no way Tailwind could bypass scoping automatically (maybe it would even be an unexpected pattern if it did that?).

Upvotes: 0

Related Questions