Monorepo & Content Scope
If you use csszyx inside a monorepo and your build fails with something like
Cannot find module './h.cur', an invalid url() in your CSS, or a cryptic
hashing crash deep in the bundler — this page is the fix. It is a one-time, two-line
change to your CSS entry, and it is not specific to any framework: it applies to
Vite, Next.js (webpack and Turbopack), Astro, and any bundler running Tailwind v4.
What’s actually happening
Section titled “What’s actually happening”Tailwind v4 has automatic content detection — no content: [...] array. It picks
a base directory and scans it for class names. In a monorepo, that base climbs up to
the workspace root, so Tailwind scans every package — and the files it scans are
not just your components.
Tailwind ignores node_modules, .gitignored files, binaries, CSS, and lockfiles —
but it does not ignore .md, .mdx, or .txt. Documentation is full of class
names written as examples: a README code block, an MDX snippet, an AI-context file
like llms-full.txt. Tailwind can’t tell “example in the docs” from “class in my app”,
so it generates CSS for them — including arbitrary-value classes that compile to broken
url(...) rules.
The fix: scope the scan to your package
Section titled “The fix: scope the scan to your package”Disable automatic detection and tell Tailwind exactly what to scan. csszyx already
auto-injects an @source for the classes it generates, so you only add your own
templates.
@import "tailwindcss" source(none);@source ".."; /* your package root, relative to this CSS file */source(none) turns off the climb-to-the-workspace-root scan; the explicit @source
adds back only your package. This is the most reliable form — a narrowing
source("..") alone is not enough, because automatic detection can still escape the
base in some bundler pipelines.
Other ways to scope
Section titled “Other ways to scope”Disable detection, then list what to scan. Deterministic; nothing leaks in.
@import "tailwindcss" source(none);@source ".."; /* this package */@source "../../packages/ui/src"; /* a shared UI lib you import classes from */Keep automatic detection but carve out the poisoners. Simpler, but you must name every offending path.
@import "tailwindcss";@source not "../../apps/docs"; /* docs with class examples */@source not "../../**/*.md"; /* and any markdown */Point detection at a sub-tree. Convenient, but less reliable — some pipelines
still climb out of the base, so prefer source(none) if you see leakage.
@import "tailwindcss" source("../src");Safelisting literal classes
Section titled “Safelisting literal classes”source(none) only affects scanning. If you generate class names dynamically (or
need a class that appears in no file), safelist it with @source inline(...) — it
supports brace expansion and ranges:
@source inline("underline");@source inline("{hover:,focus:,}bg-blue-{50,{100..900..100},950}");How csszyx fits in
Section titled “How csszyx fits in”csszyx compiles your sz props to Tailwind classes and writes them to a generated
safelist file (csszyx-classes.html), then auto-injects an @source pointing at
it. That is why, even with source(none), your csszyx styles still emit — the plugin
already registered its own source. You only ever scope your own templates.
See also
Section titled “See also”- Installation — first-time setup.
- Tailwind CSS — Detecting classes in source files (official
source()/@sourcereference).