Skip to content

Tailwind v4 doesn't generate CSS variables when using @config directive #18237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jakubmazanec opened this issue Jun 5, 2025 · 4 comments
Closed

Comments

@jakubmazanec
Copy link

jakubmazanec commented Jun 5, 2025

What version of Tailwind CSS are you using?

v4.1.8

What build tool (or framework if it abstracts the build tool) are you using?

Vite 6.3.5

What version of Node.js are you using?

v24.1.0

What browser are you using?

Chrome

What operating system are you using?

Windows

Reproduction URL

https://github.com/jakubmazanec/tailwind-css-variables-bug

Describe your issue

When using the old JS config (I need it, because my color palette is JS-generated; there really should be a way how to pass JS values to the new CSS config), colors defined in it work, but no CSS variable is created for them.

In the reproduction, Tailwind class text-tahiti that uses color defined in the JS config leads to color: #3ab7bf;, but class text-midnight leads to color: var(--color-midnight); and root has --color-midnight: #121063;.

Is there a workaround for this bug? I would like to finish the upgrade soon. Thank you.

Edit: CSS variables are probably not created for other JS config theme definitions, e.g. fontFamily.

@jakubmazanec
Copy link
Author

Possibly related #17896.

@wongjn
Copy link
Collaborator

wongjn commented Jun 5, 2025

A workaround could be to use addBase() to explicitly generate the CSS variables:

import plugin from "tailwindcss/plugin";
import colors from "./my-color-palette";

export default {
  theme: {
    /**
     * Convert `colors` into an object shape like:
     * {
     *   tahiti: 'var(--color-tahiti)',
     * }
     */
    colors: ,
  },
  plugins: [
    plugin(({ addBase }) => {
      addBase({
        /**
         * Convert `colors` into an object shape like:
         * {
         *   '--color-tahiti': '#3ab7bf',
         * }
         */
        ':root': ,
      });
    }),
  ],
}; 

@jakubmazanec
Copy link
Author

@wongjn Thank you for the workaround.

@RobinMalfait
Copy link
Member

Hey!

I would probably recommend the workaround that @wongjn provided.

When you are using @config you are using the v3 backwards compatible way of handling the tailwind.config.js file. We therefore use the same behavior as if you used Tailwind CSS v3 which is to immediately inline the values instead of creating a CSS variable. Suddenly creating a CSS variable out of it would and could result in different runtime behavior.

In the v3 docs we have a section that talks about CSS variables, which is essentially the workaround that @wongjn mentioned. More info: https://v3.tailwindcss.com/docs/customizing-colors#using-css-variables

You could also create a Vite plugin that injects generated CSS (via JS) using something like:

diff --git a/src/index.css b/src/index.css
index 8bfb183..94c6318 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,5 +1,4 @@
 @import 'tailwindcss';
-@config '../tailwind.config.js';
 
 @theme {
   --color-midnight: #121063;
diff --git a/vite.config.ts b/vite.config.ts
index 0fee922..b859480 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,30 @@
+import fs from 'node:fs/promises';
 import {defineConfig} from 'vite';
 import react from '@vitejs/plugin-react';
 import tailwindcss from '@tailwindcss/vite';
 
 export default defineConfig({
-  plugins: [tailwindcss(), react()],
+  plugins: [injectGeneratedCSS(), tailwindcss(), react()],
 });
+
+const css = String.raw;
+export function injectGeneratedCSS() {
+  return {
+    name: 'vite-plugin-inject-css',
+
+    async load(id: string) {
+      if (id.endsWith('/index.css')) {
+        const original = await fs.readFile(id, 'utf-8');
+
+        // Generate the CSS to be injected
+        const injected = css`
+          @theme {
+            --color-tahiti: #3ab7bf;
+          }
+        `;
+
+        return original + '\n' + injected;
+      }
+    },
+  };
+}

That way CSS variables will be used and defined:

Image Image

Going to close this for now since this is expected behavior. Hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants