Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save TwoSquirrels/4cc644e518fa2e9c0371cf5e40dba0ee to your computer and use it in GitHub Desktop.

Select an option

Save TwoSquirrels/4cc644e518fa2e9c0371cf5e40dba0ee to your computer and use it in GitHub Desktop.
How to fix Nuxt UI v4 dynamic classes & styles issues with Tailwind CSS v4 in nuxt dev

How to fix Nuxt UI v4 dynamic classes & styles issues with Tailwind CSS v4 in nuxt dev

When using Nuxt UI v4 with Tailwind CSS v4, the JIT compiler often fails to detect dynamic classes generated by Nuxt UI components (e.g., bg-primary-500) during development (nuxt dev). This results in missing styles and broken UI.

This solution forces the JIT engine to recognize these classes by explicitly defining them in a separate CSS file that is only loaded in the development environment.

Usage

1. Create main.dev.css

Copy the content of main.dev.css (attached in this Gist) to your project's assets directory. Put it in the same place as main.css.

Example path: app/assets/main.dev.css

2. Update nuxt.config.ts

Modify your nuxt.config.ts to load dev.css only when in development mode. This prevents the production build from being bloated with unnecessary class definitions.

  export default defineNuxtConfig({
    // ...
  
    modules: [
      '@nuxt/ui',
      // ...
    ],
  
    css: [
-     '~/assets/main.css',
+     process.env.NODE_ENV === 'development' ? '~/assets/main.dev.css' : '~/assets/main.css',
    ],
  
    // ...
  });

Now, restart your development server (nuxt cleanup && nuxt dev), and the styles should appear correctly.

Troubleshooting: VS Code Linting Errors

You might see a red squiggly line on the @source inline(...) directives with the message:

POSIX-style paths are required with source(…)

This is a false positive caused by the Tailwind CSS IntelliSense extension misinterpreting the escaped brackets (e.g., \[) inside the string as Windows file paths. The code works correctly despite this warning.

To suppress this error, add the following configuration to your VS Code settings (e.g., inside .vscode/settings.json):

  {
    // ...
+   "tailwindCSS.lint.invalidSourceDirective": "ignore",
  }
/* SPDX-License-Identifier: CC0-1.0 */
@import "./main.css";
/*
* Workaround for Nuxt UI styles not loading in the development server.
* https://github.com/nuxt/ui/issues/3374#issuecomment-2681066400
*/
@source "../../node_modules/@nuxt/ui";
/*
* Workaround for Nuxt UI dynamic color classes not being recognized by Tailwind CSS v4 JIT in dev mode.
*/
@source inline("{bg,text,ring,border,outline,divide}-{primary,secondary,success,info,warning,error}{,/{5,10,15,20,25,30,40,50,60,70,75,80,90,95}}");
@source inline("text-{primary,secondary,success,info,warning,error}-{50,100,200,300,400,500,600,700,800,900,950}");
@source inline("hover:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20,25,50,75,90,95}}");
@source inline("hover:{text,border,ring,outline}-{primary,secondary,success,info,warning,error}{,/{25,50,75}}");
@source inline("group-hover:text-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("active:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20,25,50,75,90,95}}");
@source inline("active:{text,border,ring}-{primary,secondary,success,info,warning,error}{,/{25,50,75}}");
@source inline("focus:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20}}");
@source inline("focus:{border,ring,outline}-{primary,secondary,success,info,warning,error}{,/{25,50}}");
@source inline("focus-visible:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20}}");
@source inline("focus-visible:{border,ring,outline}-{primary,secondary,success,info,warning,error}{,/{25,50}}");
@source inline("focus-within:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15}}");
@source inline("focus-within:{border,ring}-{primary,secondary,success,info,warning,error}");
@source inline("has-focus-visible:border-{primary,secondary,success,info,warning,error}{,/{25,50}}");
@source inline("has-focus-visible:ring-{primary,secondary,success,info,warning,error}{,/{25,50}}");
@source inline("disabled:bg-{primary,secondary,success,info,warning,error}{,/{5,10,25,50}}");
@source inline("disabled:{text,border,ring}-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("aria-disabled:bg-{primary,secondary,success,info,warning,error}{,/{5,10,25,50}}");
@source inline("aria-disabled:{text,border}-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("aria-checked:bg-{primary,secondary,success,info,warning,error}{,/{10,20}}");
@source inline("aria-selected:bg-{primary,secondary,success,info,warning,error}{,/{10,20}}");
@source inline("before:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20}}");
@source inline("before:{border,ring}-{primary,secondary,success,info,warning,error}");
@source inline("after:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20}}");
@source inline("after:{border,ring}-{primary,secondary,success,info,warning,error}");
@source inline("{placeholder,caret,accent}:-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("marker:text-{primary,secondary,success,info,warning,error}{,/{25,50,75}}");
@source inline("selection:bg-{primary,secondary,success,info,warning,error}{,/{10,20,25}}");
@source inline("selection:text-{primary,secondary,success,info,warning,error}");
@source inline("dark:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20,25,50,75,90}}");
@source inline("dark:text-{primary,secondary,success,info,warning,error}{,-{200,300,400,500,600}}{,/{50,75}}");
@source inline("dark:{border,ring,outline}-{primary,secondary,success,info,warning,error}{,/{25,50,75}}");
@source inline("dark:hover:bg-{primary,secondary,success,info,warning,error}{,/{10,15,20,75}}");
@source inline("dark:focus-visible:ring-{primary,secondary,success,info,warning,error}");
@source inline("dark:hover:text-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("dark:active:bg-{primary,secondary,success,info,warning,error}{,/{10,15,20,75}}");
@source inline("dark:active:text-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("hover:bg-{primary,secondary,success,info,warning,error}");
@source inline("hover:text-{primary,secondary,success,info,warning,error}/75");
@source inline("active:text-{primary,secondary,success,info,warning,error}/75");
@source inline("hover:border-{primary,secondary,success,info,warning,error}");
@source inline("data-\\[selected\\]:bg-{primary,secondary,success,info,warning,error}{,/{5,10,15,20}}");
@source inline("data-\\[selected\\]:text-{primary,secondary,success,info,warning,error}{,/{50,75}}");
@source inline("data-\\[selected\\]:ring-{primary,secondary,success,info,warning,error}{,/{25,50}}");
@source inline("data-\\[highlighted\\]:bg-{primary,secondary,success,info,warning,error}{,/{10,20}}");
@source inline("hover:not-data-\\[selected\\]:bg-{primary,secondary,success,info,warning,error}{,/{10,20}}");
@source inline("data-today:not-data-\\[selected\\]:text-{primary,secondary,success,info,warning,error}");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment