If installed PyColors components render as plain content, check whether their
utilities exist in the generated CSS. In the Tailwind v4 reproduction below,
adding @source for the installed package fixes the missing styles. Installing
the package and passing a production build are not enough.
For app/globals.css, the complete stylesheet is:
@import "tailwindcss";
@import "@pycolors/tokens/tokens.css";
@source "../node_modules/@pycolors/ui/dist";
@custom-variant dark (&:where(.dark, .dark *));
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}Already importing Tailwind and PyColors tokens? Add only the missing @source
line. Keep the imports at the top; do not duplicate the token mappings.
Read the PyColors UI installation guide for the canonical setup and requirements.
Revised September 28, 2026: verified against the public npm packages and production consumer described below. Original publication: March 17, 2026.
Use the path relative to your stylesheet
The two tested layouts need different registrations:
| Global stylesheet | Source registration |
|---|---|
app/globals.css | @source "../node_modules/@pycolors/ui/dist"; |
src/app/globals.css | @source "../../node_modules/@pycolors/ui/dist"; |
Tailwind v4 ignores node_modules during automatic detection. An explicit
@source opts this package in; its path starts at the stylesheet, not the
terminal's working directory. See Tailwind's source detection documentation.
Use the installed package's dist directory for this npm consumer. A workspace
that imports local source has a different location: resolve that location from
its stylesheet. Scanning an entire monorepo or all of node_modules is unnecessary.
What the failing build actually showed
The example uses the public Card and Button exports without adding their
internal classes to the app. Both the failing and corrected versions passed
TypeScript checking and a production build.
| Condition | Generated CSS | Browser result |
|---|---|---|
| Tokens loaded, no library registration | No .inline-flex, .bg-primary or .bg-card rule | Link styled as a Button remains inline, transparent and unpadded |
| Wrong relative source path | Same missing rules | Same unstyled components |
| Correct source path | All three rules present | Button uses inline-flex, a 36px height and 8px/16px padding; Button and Card have themed backgrounds |
| Correct source, primary/card mappings disabled | Layout rule present; both background rules absent | Button keeps its layout but both surfaces are transparent |
The source-path results were verified for both stylesheet locations. The
last row is a separate negative control: the test resets only
--color-primary and --color-card to initial inside @theme. It leaves the
underlying CSS variables loaded. Do not add that reset to your application.
These utilities were never generated in the missing-source case; they were not existing component styles that Tailwind subsequently removed. If the rule is present but crossed out in browser DevTools, inspect the cascade and competing CSS instead of adding more scan paths.
Reproduce with the tested public packages
The consumer ran with Node 24.18.1, pnpm 10.32.1, Next.js 16.1.1, React/React DOM 19.2.0, Tailwind CSS and its PostCSS plugin 4.3.3, PostCSS 8.5.28, UI 1.5.4, and tokens 1.2.3. These are tested pins, not a promise about every compatible version.
Create an empty directory outside a monorepo and add the files below. With Node 24 and pnpm 10.32.1 available, run:
pnpm install --ignore-scripts --prod=false
pnpm types:check
pnpm build
pnpm startThe manifest pins every direct dependency. This first install resolves
transitive dependencies and creates pnpm-lock.yaml; keep that file and use
pnpm install --frozen-lockfile --ignore-scripts --prod=false for subsequent
installs. A later first install can resolve different transitive versions, so
record your lockfile when comparing results. No repository access, workspace
links or copied component implementations are needed.
{
"name": "pycolors-tailwind-consumer",
"private": true,
"type": "module",
"packageManager": "pnpm@10.32.1",
"engines": { "node": ">=24 <25" },
"scripts": {
"build": "next build --webpack",
"types:check": "next typegen && tsc --noEmit",
"start": "next start"
},
"dependencies": {
"@pycolors/ui": "1.5.4",
"@pycolors/tokens": "1.2.3",
"lucide-react": "1.47.0",
"next": "16.1.1",
"react": "19.2.0",
"react-dom": "19.2.0"
},
"devDependencies": {
"@tailwindcss/postcss": "4.3.3",
"tailwindcss": "4.3.3",
"postcss": "8.5.28",
"@types/node": "24.12.0",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"typescript": "6.0.3"
}
}export default { plugins: { "@tailwindcss/postcss": {} } };This is the Tailwind v4 PostCSS setup described in the
official Next.js framework guide.
Use the app/globals.css shown at the start of this article, then add:
import type { ReactNode } from "react";
import "./globals.css";
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}import {
Button,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@pycolors/ui";
export default function Page() {
return (
<main>
<Card>
<CardHeader>
<CardTitle>Installed components</CardTitle>
<CardDescription>
Check the package styles in your app.
</CardDescription>
</CardHeader>
<CardContent>
<Button asChild>
<a href="https://pycolors.io/docs/ui/usage-patterns">
Explore usage patterns
</a>
</Button>
</CardContent>
</Card>
</main>
);
}{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [{ "name": "next" }]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}declare module "*.css";node_modules/
.next/
next-env.d.ts
*.tsbuildinfoThe CSS declaration supports the side-effect stylesheet import with the tested
TypeScript 6.0.3 setup. Keep .next out of source detection, and keep diagnostic
scripts and expected class strings outside the consumer. Otherwise the test
itself can accidentally make Tailwind generate the missing utilities.
For the second layout, move the complete app directory into src/app and
change only the source registration to the second path in the table. Rebuild
from a clean .next directory. Both layouts were tested with fresh production
output for every condition.
Check production CSS, then the browser
Temporarily remove the @source line from the disposable example, build again,
and inspect .next/static/css. Restore the correct line and rebuild. Search
for .inline-flex, .bg-primary and .bg-card in the emitted CSS, not just in
the component's DOM class attribute. All three should appear after the correction.
Serve the production output with pnpm start. In DevTools, inspect the computed
styles of [data-slot="button"] and [data-slot="card"]. For the corrected
example, Chromium measured these background colors:
| Surface | Light | With .dark on the document root |
|---|---|---|
| Button | oklch(0.49 0.23 292) | oklch(0.68 0.19 292) |
| Card | oklch(0.99 0 0) | oklch(0.19 0.008 285) |
Wait for color transitions to finish before measuring. Your application owns its existing theme selection; PyColors does not require a new provider. This check covers this composition's styles, not an accessibility certification.
Distinguish source detection from token setup
The public @pycolors/tokens/tokens.css import already supplies the theme values
and their Tailwind v4 semantic mappings. A --primary value alone does not
define a bg-primary utility. The mapping and a detected class are both needed.
Our separate negative control demonstrates this: layout survives, while the
two intentionally unmapped background utilities disappear.
Keep the supported import once, and remove conflicting theme resets rather than copying a second mapping layer. Continue with the theming guide or semantic design tokens article when the remaining problem is theme values rather than missing utilities.
In your own components, write complete class names. Tailwind scans text; it
does not evaluate strings such as bg-${color}-500. Map a prop to complete
static alternatives instead. This follows the
official class detection guidance.
A note for readers of the earlier Tailwind v3 recipe
The earlier version of this article used tailwind.config content paths, a
Tailwind v3 convention. Tailwind v4 does not automatically detect JavaScript
configuration files; see the upgrade guide.
The tested PyColors setup here uses v4 CSS configuration. This reproduction
does not establish compatibility of these package versions with Tailwind v3.
Package download failures, ESLint configuration and deployment logs are separate diagnostics. Changing from pnpm to npm does not supply a missing source path; this entire reproduction uses pnpm.
Final checks
- Resolve the narrow package source path from the actual stylesheet location.
- Import the public tokens stylesheet once and preserve its semantic mappings.
- Verify generated utilities in a fresh production build.
- Inspect computed component styles in both themes; investigate overrides when rules exist.
- Keep complete class names and avoid diagnostic files contaminating source detection.
Read the PyColors UI installation guide, then use UI usage patterns to build the next screen.