tailwindcss icon indicating copy to clipboard operation
tailwindcss copied to clipboard

Tailwind CSS v4 Selector Parsing Issue with Empty String Attribute

Open coderrshyam opened this issue 9 months ago • 6 comments

Tailwind CSS v4 Selector Parsing Issue with Empty String Attribute

Environment

  • Tailwind CSS Version: 4.0.7
  • Framework: Next.js 15.1.7
  • Node.js Version: 22.14.0
  • Browser: Chrome
  • Operating System: Windows

Reproduction

Repository: https://github.com/coderrshyam/next.js-hook-webpack-error

Steps to Reproduce:

  1. Clone the repository:
git clone https://github.com/coderrshyam/next.js-hook-webpack-error.git
cd next.js-hook-webpack-error
  1. Install dependencies:
pnpm install
  1. Attempt to build the project:
pnpm build

Issue Description:

When attempting to build a Next.js project with Tailwind CSS v4, an issue occurs with CSS selector parsing, specifically for selectors containing attribute selectors with empty string values.

The problematic selector: .prose code[data-theme*=" "]

Behavior in Tailwind CSS v3 (Working Correctly)

In Tailwind CSS v3, the selector is parsed correctly:

Parser {
  rule: '.prose code[data-theme*=" "]',
  options: { lossy: false, safe: false },
  position: 8,
  css: '.prose code[data-theme*=" "]',
  // ... other properties
}

Behavior in Tailwind CSS v4 (Incorrect)

In Tailwind CSS v4, the selector is not parsed correctly:

Parser {
  rule: '.prose code[data-theme*=\\]',
  options: { lossy: false, safe: false },
  position: 8,
  css: '.prose code[data-theme*=\\]', 
  // ... other properties
}

Expected Behavior

The parser in Tailwind CSS v4 should correctly handle the empty string in the attribute selector, similar to how it was handled in v3.

Actual Behavior

The parser in Tailwind CSS v4 seems to be escaping or misinterpreting the empty string in the attribute selector, leading to an incorrect parsing of the CSS rule.

Additional Notes

  • This issue specifically occurs during the build process of a Next.js project.
  • The problem appears to be isolated to cases where an attribute selector contains an empty string value.

coderrshyam avatar Feb 19 '25 13:02 coderrshyam

Hey! This seems like an issue in the upstream handling of the CSS file, I can reproduce this without Tailwind CSS. The reason is that we minify the selector you mentioned to something like this (in it's most minimal form):

[data-attr=\ ] {
  color: red;
}

This works in the browsers but will trip up Next.js/webpack right now.

I created an upstream bug report for this: https://github.com/vercel/next.js/issues/76269

philipp-spiess avatar Feb 20 '25 10:02 philipp-spiess

ok

coderrshyam avatar Feb 20 '25 10:02 coderrshyam

@philipp-spiess is there is plan to support ts config file for postcss

coderrshyam avatar May 10 '25 17:05 coderrshyam

@coderrshyam I'd assume it should already work since we use jiti to load the config files. If you see any issues there please file a new bug report, thanks!

philipp-spiess avatar May 12 '25 09:05 philipp-spiess

"Nice work, @philipp-spiess! Could you create a pull request in Next.js to support this TypeScript configuration file for PostCSS as well? I had previously created a PR (#79054), but it contains errors and couldn't be merged."

coderrshyam avatar May 12 '25 09:05 coderrshyam

@coderrshyam I'm afraid that's not something we can help with, I don't know why Next.js limits the type of the PostCSS config file but my gut tells me it's there for a reason. Best to reach out to the Next.js maintainers for this!

philipp-spiess avatar May 12 '25 09:05 philipp-spiess

Since there's an open issue for this for Next.js I'm gonna close this one here. There's not much we can do on our side.

There are, however, two workarounds!

  1. Update to the latest Next.js and build using --turbopack. Turbopack uses different mechanisms to parse CSS and appears to handle this case fine; OR
  2. Disable minification by passing in options to our PostCSS plugin:
/** @type {import('tailwindcss').Config} */
export default {
  plugins: {
    "@tailwindcss/postcss": {
      // If you add this you can disable minification but still run Lightning CSS
      optimize: { minify: false },
    },
  },
};

thecrypticace avatar Sep 18 '25 19:09 thecrypticace