From data-science
Documents Tailwind CSS v4 + shadcn/ui integration patterns for PolicyEngine frontend projects, covering @theme namespaces, CSS variable conventions, and common mistakes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/data-science:policyengine-tailwind-shadcn-skillThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Technical reference for how PolicyEngine's CSS-first design token architecture works. This skill explains the **mechanism** — how Tailwind v4 and shadcn/ui consume CSS variables. For the actual **token values** (colors, fonts, spacing), see `policyengine-design-skill`.
Technical reference for how PolicyEngine's CSS-first design token architecture works. This skill explains the mechanism — how Tailwind v4 and shadcn/ui consume CSS variables. For the actual token values (colors, fonts, spacing), see policyengine-design-skill.
PolicyEngine uses a single CSS file (@policyengine/ui-kit/theme.css) as the source of truth for all design tokens. This file has three layers:
Layer 1: :root { --primary: #2C7A7B; } ← Raw values (shadcn/ui convention)
Layer 2: @theme inline { --color-primary: var(--primary); } ← Bridge to Tailwind
Layer 3: @theme { --color-teal-500: #319795; } ← Brand palette + fonts + sizes
Consumers import it in their globals.css:
@import "tailwindcss";
@import "@policyengine/ui-kit/theme.css";
@theme namespacesTailwind v4 uses CSS custom properties in @theme blocks to generate utility classes. The namespace prefix determines which utilities are created:
| CSS variable prefix | Tailwind utility | Example variable | Example class |
|---|---|---|---|
--color-* | bg-*, text-*, border-*, fill-* | --color-primary: #2C7A7B | bg-primary, text-primary |
--color-teal-* | bg-teal-*, text-teal-* | --color-teal-500: #319795 | bg-teal-500 |
--text-* | text-* (font size) | --text-sm: 14px | text-sm |
--font-* | font-* | --font-sans: Inter, ... | font-sans |
--radius-* | rounded-* | --radius-lg: 8px | rounded-lg |
--spacing-* | p-*, m-*, gap-*, w-*, h-* | --spacing-header: 58px | h-header |
--breakpoint-* | sm:, md:, lg: | --breakpoint-md: 62rem | md:flex-col |
Source: Tailwind v4 Theme docs
@theme vs @theme inline/* @theme — bakes values directly into generated CSS */
@theme {
--color-teal-500: #319795; /* Resolved at build time */
}
/* @theme inline — preserves var() for runtime resolution */
@theme inline {
--color-primary: var(--primary); /* Resolved at runtime via :root */
}
When to use @theme inline:
:root CSS variable (var(--something)):root values change, Tailwind must re-resolve)When to use @theme:
#319795, 14px, Inter)Source: Tailwind v4 Functions and Directives
shadcn/ui defines semantic tokens as unprefixed CSS variables in :root:
:root {
--primary: #2C7A7B;
--background: #FFFFFF;
--foreground: #000000;
--muted: #F2F4F7;
--muted-foreground: #6B7280;
--border: #E2E8F0;
--chart-1: #319795;
--chart-2: #0EA5E9;
/* ... */
}
These are then bridged to Tailwind via @theme inline:
@theme inline {
--color-primary: var(--primary); /* → bg-primary, text-primary */
--color-background: var(--background); /* → bg-background */
--color-foreground: var(--foreground); /* → text-foreground */
--color-chart-1: var(--chart-1); /* → fill-chart-1 */
}
Source: shadcn/ui Theming, shadcn/ui Tailwind v4 guide
var() in RechartsModern browsers resolve CSS custom properties in SVG presentation attributes. Recharts fill and stroke props accept var() directly:
<Bar fill="var(--chart-1)" />
<Line stroke="var(--chart-2)" />
<CartesianGrid stroke="var(--border)" />
No helper function needed. The old getCssVar() / getComputedStyle() pattern is unnecessary.
Source: shadcn/ui Charts
:root (shadcn/ui semantic)| Variable | Hex | Usage |
|---|---|---|
--primary | #2C7A7B | Primary actions, buttons |
--primary-foreground | #FFFFFF | Text on primary |
--background | #FFFFFF | Page background |
--foreground | #000000 | Body text |
--muted | #F2F4F7 | Muted backgrounds |
--muted-foreground | #6B7280 | Secondary text |
--border | #E2E8F0 | Borders, dividers |
--card | #FFFFFF | Card backgrounds |
--destructive | #DC2626 | Error states (red-600, clears WCAG AA on the white --destructive-foreground) |
--ring | #319795 | Focus rings |
--chart-1 through --chart-5 | Teal→Gray | Chart series |
@theme inline (bridges)Maps each :root var to Tailwind's --color-* namespace. Example:
--color-primary: var(--primary) → enables bg-primary, text-primary--color-chart-1: var(--chart-1) → enables fill-chart-1@theme (brand palette)| Namespace | Example | Tailwind class |
|---|---|---|
--color-teal-* | --color-teal-500: #319795 | bg-teal-500 |
--color-gray-* | --color-gray-600: #4B5563 | text-gray-600 |
--color-blue-* | --color-blue-500: #0EA5E9 | bg-blue-500 |
--text-* | --text-sm: 14px | text-sm |
--font-* | --font-sans: Inter, ... | font-sans |
--spacing-* | --spacing-header: 58px | h-header |
@theme instead of @theme inline for var() references/* WRONG — var() won't resolve, Tailwind bakes the literal string */
@theme {
--color-primary: var(--primary);
}
/* CORRECT — var() resolves at runtime */
@theme inline {
--color-primary: var(--primary);
}
/* WRONG — creates a utility called "primary", not a color */
@theme {
--primary: #2C7A7B;
}
/* CORRECT — --color-* prefix creates bg-primary, text-primary */
@theme inline {
--color-primary: var(--primary);
}
// WRONG — unnecessary helper
const color = getCssVar('--chart-1');
<Bar fill={color} />
// CORRECT — SVG accepts var() directly
<Bar fill="var(--chart-1)" />
// WRONG
<div style={{ color: '#319795' }}>
// CORRECT — use Tailwind class
<div className="text-teal-500">
// CORRECT — use CSS var for inline styles
<div style={{ color: 'var(--primary)' }}>
Tailwind v4 does NOT use tailwind.config.ts. All configuration is in CSS via @theme blocks. The ui-kit theme CSS file handles this.
// WRONG — old convention
<div className="bg-pe-primary-500 text-pe-text-secondary p-pe-lg">
// CORRECT — standard Tailwind/shadcn classes
<div className="bg-teal-500 text-muted-foreground p-4">
policyengine-design-skill — Token values, color tables, chart brandingpolicyengine-frontend-builder-spec-skill — Mandatory technology requirementspolicyengine-recharts-skill — Chart-specific patternspolicyengine-interactive-tools-skill — Standalone tool scaffoldingnpx claudepluginhub policyengine/policyengine-claude --plugin analysis-toolsGuides setup and debugging of @policyengine/ui-kit in consumer apps: PostCSS config, globals.css import order, Tailwind v4 utility generation, and PolicyEngineShell usage.
Sets up Tailwind v4 + shadcn/ui theming in React/Vite projects: installs deps, configures CSS variables with @theme inline, adds dark mode support, verifies. Fixes v4 colors, animations, @apply, migration issues.
Sets up Tailwind CSS v4 with shadcn/ui in Vite + React projects. Covers dark mode via ThemeProvider, CSS variables, @theme inline, vite.config, and v3 migration. Fixes theming issues.