Skip to content
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

v4. build fails with dynamically created classnames + at-rules #15853

Open
homeboldham opened this issue Jan 25, 2025 · 4 comments
Open

v4. build fails with dynamically created classnames + at-rules #15853

homeboldham opened this issue Jan 25, 2025 · 4 comments
Assignees

Comments

@homeboldham
Copy link

homeboldham commented Jan 25, 2025

What version of Tailwind CSS are you using?

4.0.0

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

vite-6.0.11

What version of Node.js are you using?

v23.4.0

What browser are you using?

Firefox, but it doesn't matter

What operating system are you using?

macOS

Reproduction URL

https://github.com/homeboldham/vite-tailwind-unknown-word

it's a minimal vite + tailwind setup (using vite react ts template) and adding tailwind v4 via @tailwindcss/vite plugin.

Describe your issue

Please check https://github.com/homeboldham/vite-tailwind-unknown-word/blob/main/src/App.tsx
If you have smth like h-[${h}px] in your source code,
AND
you have at-rule in your css. For example, I add font import here:
https://github.com/homeboldham/vite-tailwind-unknown-word/blob/main/src/index.css

then the build fails:

> [email protected] build
> tsc -b && vite build

vite v6.0.11 building for production...
✓ 15 modules transformed.
x Build failed in 100ms
error during build:
[vite:css] [postcss] /Users/foo/github/vite-tailwind-atrule/src/index.css:524:15: Unknown word
file: /Users/foo/github/vite-tailwind-atrule/src/index.css:524:14
    at Input.error (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/input.js:109:16)
    at Parser.unknownWord (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/parser.js:593:22)
    at Parser.other (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/parser.js:435:12)
    at Parser.parse (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/parser.js:470:16)
    at parse (/Users/foo/foo/vite-tailwind-atrule/node_modules/postcss/lib/parse.js:11:12)
    at new LazyResult (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/lazy-result.js:133:16)
    at Processor.process (/Users/foo/github/vite-tailwind-atrule/node_modules/postcss/lib/processor.js:53:14)
    at compileCSS (file:///Users/foo/github/vite-tailwind-atrule/node_modules/vite/dist/node/chunks/dep-M1IYMR16.js:48784:59)
    at async Object.transform (file:///Users/foo/github/vite-tailwind-atrule/node_modules/vite/dist/node/chunks/dep-M1IYMR16.js:48039:11)
    at async transform (file:///Users/foo/github/vite-tailwind-atrule/node_modules/rollup/dist/es/shared/node-entry.js:19794:16)

Everything works if it's just @import or h-[${h}px] alone. I can reproduce it only if they're both there.

It's not about h-. I believe any dynamically created className can cause this.

(please disregard the rationale behind the component in the code – I simplified it to nonsensical to reproduce the issue).

@wongjn
Copy link
Contributor

wongjn commented Jan 25, 2025

As an aside, h-[${h}px] shouldn't be done, as per the documentation:

Since Tailwind scans your source files as plain text, it has no way of understanding string concatenation or interpolation in the programming language you're using.

❌ Don't construct class names dynamically

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes.

Instead, make sure any class names you’re using exist in full:

✅ Always use complete class names

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

If you're using a component library like React or Vue, this means you shouldn't use props to dynamically construct classes:

❌ Don't use props to build class names dynamically

function Button({ color, children }) {
  return <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>{children}</button>;
}

Instead, you could consider doing this instead:

const H_VALUES = {
  10: 'h-[10px]',
  20: 'h-[20px]',
};

function Height({ h }: {h?: 10 | 20}) {
  const heightStyles = h ? H_VALUES[h] : '';

  return (
    <div className={`${heightStyles}`}>
      Height
    </div>
  )
}

However, regards to the error, perhaps a more graceful handling of the situation could be enacted indeed.

@homeboldham
Copy link
Author

Thanks @wongjn Yes, I expected tailwind to not recognize such classname constructs and skip them. Which it actually does if you remove the font import from index.css. The problem is the cryptic error message that only appears in combination with at-rules. If I'm not mistaken, the build doesn't fail with v3.

@RobinMalfait RobinMalfait self-assigned this Jan 29, 2025
@RobinMalfait
Copy link
Member

Hey!

We can improve the error message here, but the issue remains that we don't support dynamic class names so you will need another solution to the problem. It's true that in v3 it worked slightly different where it didn't always throw an error (but it wouldn't generate anything in the CSS either).

@Nefcanto
Copy link

@RobinMalfait a simple improvement in the error message would hugely improve the DX. Hundreds of files, each with tens of lines of code. How should I search for the error?

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

4 participants