0

I'm trying to implement dark mode in my Next.js app using TailwindCSS. However, TailwindCSS's dark: classes are not being applied, even when the .dark class is present on the <html> tag.

global.css

@import "tailwindcss";
@import "tw-animate-css";
@plugin "@tailwindcss/typography";
/* @custom-variant dark (&:is(.dark *)); */
/*
body::before {
 content: "";
 position: fixed;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 background-image: linear-gradient(
 rgba(0, 0, 0, 0.1),
 rgba(0, 0, 0, 0.1)
 ),url("/test.jpg");
 background-size: 750px;
 background-repeat: repeat;
 background-position: center;
 z-index: -1;
 pointer-events: none;
}
*/
@theme inline {
 --color-secondary: var(--color-neutral-500);
 --shadow-aceternity: 
 0px 2px 3px -1px rgba(0, 0, 0, 0.1),0px 1px 0px 0px rgba(25,28,33,0.02),
 0px 0px 0px 1px rgba(25, 28, 33, 0.08)
;
 --shadow-inset:inset 0px 0px 4px 0.1px #00000010;
 --color-sidebar-ring: var(--sidebar-ring);
 --color-sidebar-border: var(--sidebar-border);
 --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
 --color-sidebar-accent: var(--sidebar-accent);
 --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
 --color-sidebar-primary: var(--sidebar-primary);
 --color-sidebar-foreground: var(--sidebar-foreground);
 --color-sidebar: var(--sidebar);
 --color-chart-5: var(--chart-5);
 --color-chart-4: var(--chart-4);
 --color-chart-3: var(--chart-3);
 --color-chart-2: var(--chart-2);
 --color-chart-1: var(--chart-1);
 --color-ring: var(--ring);
 --color-input: var(--input);
 --color-border: var(--border);
 --color-destructive: var(--destructive);
 --color-accent-foreground: var(--accent-foreground);
 --color-accent: var(--accent);
 --color-muted-foreground: var(--muted-foreground);
 --color-muted: var(--muted);
 --color-secondary-foreground: var(--secondary-foreground);
 --color-primary-foreground: var(--primary-foreground);
 --color-popover-foreground: var(--popover-foreground);
 --color-popover: var(--popover);
 --color-card-foreground: var(--card-foreground);
 --color-card: var(--card);
 --color-foreground: var(--foreground);
 --color-background: var(--background);
 --radius-sm: calc(var(--radius) - 4px);
 --radius-md: calc(var(--radius) - 2px);
 --radius-lg: var(--radius);
 --radius-xl: calc(var(--radius) + 4px);
}
:root {
 --color-primary: var(--color-neutral-800);
 --radius: 0.625rem;
 --background: oklch(1 0 0);
 --foreground: oklch(0.145 0 0);
 --card: oklch(1 0 0);
 --card-foreground: oklch(0.145 0 0);
 --popover: oklch(1 0 0);
 --popover-foreground: oklch(0.145 0 0);
 /* --primary: oklch(0.205 0 0); */
 --primary-foreground: oklch(0.985 0 0);
 --secondary: oklch(0.97 0 0);
 --secondary-foreground: oklch(0.205 0 0);
 --muted: oklch(0.97 0 0);
 --muted-foreground: oklch(0.556 0 0);
 --accent: oklch(0.97 0 0);
 --accent-foreground: oklch(0.205 0 0);
 --destructive: oklch(0.577 0.245 27.325);
 --border: oklch(0.922 0 0);
 --input: oklch(0.922 0 0);
 --ring: oklch(0.708 0 0);
 --chart-1: oklch(0.646 0.222 41.116);
 --chart-2: oklch(0.6 0.118 184.704);
 --chart-3: oklch(0.398 0.07 227.392);
 --chart-4: oklch(0.828 0.189 84.429);
 --chart-5: oklch(0.769 0.188 70.08);
 --sidebar: oklch(0.985 0 0);
 --sidebar-foreground: oklch(0.145 0 0);
 --sidebar-primary: oklch(0.205 0 0);
 --sidebar-primary-foreground: oklch(0.985 0 0);
 --sidebar-accent: oklch(0.97 0 0);
 --sidebar-accent-foreground: oklch(0.205 0 0);
 --sidebar-border: oklch(0.922 0 0);
 --sidebar-ring: oklch(0.708 0 0);
}
.dark {
 --shadow-aceternity: 0px 2px 8px -1px rgba(255, 255, 255, 0.8),
 0px 4px 12px -2px rgba(255, 255, 255, 0.8),
 0px 0px 0px 1px rgba(255, 255, 255, 0.8);
 --color-primary: var(--color-neutral-100);
 --color-secondary: var(--color-neutral-400);
 --background: oklch(0.145 0 0);
 --foreground: oklch(0.985 0 0);
 --card: oklch(0.205 0 0);
 --card-foreground: oklch(0.985 0 0);
 --popover: oklch(0.205 0 0);
 --popover-foreground: oklch(0.985 0 0);
 /* --primary: oklch(0.922 0 0); */
 --primary-foreground: oklch(0.205 0 0);
 --secondary: oklch(0.269 0 0);
 --secondary-foreground: oklch(0.985 0 0);
 --muted: oklch(0.269 0 0);
 --muted-foreground: oklch(0.708 0 0);
 --accent: oklch(0.269 0 0);
 --accent-foreground: oklch(0.985 0 0);
 --destructive: oklch(0.704 0.191 22.216);
 --border: oklch(1 0 0 / 10%);
 --input: oklch(1 0 0 / 15%);
 --ring: oklch(0.556 0 0);
 --chart-1: oklch(0.488 0.243 264.376);
 --chart-2: oklch(0.696 0.17 162.48);
 --chart-3: oklch(0.769 0.188 70.08);
 --chart-4: oklch(0.627 0.265 303.9);
 --chart-5: oklch(0.645 0.246 16.439);
 --sidebar: oklch(0.205 0 0);
 --sidebar-foreground: oklch(0.985 0 0);
 --sidebar-primary: oklch(0.488 0.243 264.376);
 --sidebar-primary-foreground: oklch(0.985 0 0);
 --sidebar-accent: oklch(0.269 0 0);
 --sidebar-accent-foreground: oklch(0.985 0 0);
 --sidebar-border: oklch(1 0 0 / 10%);
 --sidebar-ring: oklch(0.556 0 0);
}
@layer base {
 * {
 @apply border-border outline-ring/50;
 }
 body {
 @apply bg-background text-foreground;
 }
}

heading.tsx

"use client";
import React from "react";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
const Heading = ({
 as: Tag = "h1",
 children,
 className,
}: {
 as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
 children: React.ReactNode;
 className?: string;
}) => {
 return (
 <motion.div
 initial={{ opacity: 0, filter: "blur(10px)", y: 10 }}
 whileInView={{ opacity: 1, filter: "blur(0px)", y: 0 }}
 transition={{ duration: 0.3, ease: "easeInOut" }}
 viewport={{ once: true }}
 >
 <Tag
 className={cn(
 "text-primary dark:text-primary px-4 text-2xl font-bold tracking-tighter drop-shadow-lg md:text-4xl",
 className,
 )}
 >
 {children}
 </Tag>
 </motion.div>
 );
};
export default Heading;

When I switch to dark mode:

  • Background and foreground colors update correctly.
  • But Tailwind’s dark: variant does not work (e.g., dark:text-primary).

I already verified that:

  • .dark class exists on <html>
  • Tailwind is configured with darkMode: "class"

Why are Tailwind dark: classes not applying, even though the .dark class is set?

rozsazoltan
18.2k8 gold badges49 silver badges146 bronze badges
asked 4 hours ago
New contributor
Abhinav Shinde is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
2
  • This question is similar to: How to use custom color themes in TailwindCSS v4. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented 2 hours ago
  • You haven't configured Tailwind CSS v4's dark mode correctly. You incorrectly assumed you need to set the darkMode property in tailwind.config.js. I think this is essentially a duplicate of the v4 'how to configure a theme' (e.g., a dark theme) question. Commented 2 hours ago

2 Answers 2

1

By default the dark: variant uses @media (prefers-color-scheme: dark) instead of a class name.

Thus, to get dark: to work with the dark class name, consider uncommenting the line:

/* @custom-variant dark (&:is(.dark *)); */

Or use the one explicitly given in the docs:

@custom-variant dark (&:where(.dark, .dark *));

This will modify the dark: variant to apply based on the dark class name.

answered 4 hours ago
Sign up to request clarification or add additional context in comments.

Comments

-1

Your @theme inline block and custom CSS variables override all color utilities, but they don’t define Tailwind’s actual color tokens.

Tailwind generates:

.dark .text-primary { color: theme("colors.primary") }

But your global CSS overrides --primary and --primary-foreground directly inside .dark.

And since your base layer forces:

* {
 @apply border-border outline-ring/50;
}

And:

body {
 @apply bg-background text-foreground;
}

Those use CSS variables, which override internal Tailwind utilities, including dark: variants.

Tailwind’s dark: variant only works if .dark is on <html> or <body>.

Jeremy Caney
7,807115 gold badges58 silver badges86 bronze badges
answered 4 hours ago
New contributor
W. B. is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.