# Tailwind in Zeb Templates
The RWE engine processes Tailwind utility classes at compile time without Node.js or an npm build step. Zebflow targets the high-frequency **Tailwind CSS 3.4 LTS** class contract used by existing themes and component libraries.
Compatibility is tested by CSS meaning, not only by whether a class produces a rule. Unsupported utilities are ignored rather than translated into an unrelated property.
## Compatibility Boundary
Built in:
- the standard v3 spacing, sizing, layout, flexbox, grid, typography, color, border, effect, table, transform, filter, interaction, SVG, and accessibility families used by common application themes
- composable transforms, filters, gradients, shadows, and rings
- responsive, state, structural, `group-*`, `peer-*`, `has-*`, `aria-*`, `data-*`, `supports-*`, direction, orientation, print, and pseudo-element variants
- arbitrary values such as `w-[320px]` and explicit CSS variables such as `bg-[var(--color-product)]`
- OXC source discovery for conditional classes in TSX and JavaScript string literals
Not part of the current contract:
- loading `tailwind.config.js`
- executing third-party Tailwind plugins
- automatically importing npm packages
- Tailwind v4-only syntax and utilities
Use project CSS for plugin-specific class systems. Do not assume that a third-party plugin class exists merely because its name starts with `prose-`, `form-`, or another familiar prefix.
---
## Standard Tailwind 3.4 Utilities
```tsx
<div className="flex items-center gap-4 p-6 rounded-xl border">
<h1 className="text-2xl font-bold text-slate-900">Title</h1>
<p className="text-slate-500 text-sm">Subtitle</p>
</div>
```
---
## Semantic Color Tokens
Zeb defines `--color-*` CSS custom properties that resolve to the active theme (dark or light). Use semantic token classes instead of hardcoded palette values for theme-aware UI.
### Theme tokens (per-theme, change with dark/light)
| `bg-bg` | background-color | Page background |
| `bg-surface` | background-color | Card / panel background |
| `bg-surface-2` | background-color | Nested panel |
| `bg-surface-3` | background-color | Deeply nested / hover target |
| `text-body` | color | Primary text |
| `text-body-soft` | color | Secondary / muted text |
| `text-body-muted` | color | Placeholder / hint text |
| `text-accent` | color | Brand orange highlight |
| `bg-accent` | background-color | Accent fill |
| `border-border` | border-color | Standard border |
| `border-border-soft` | border-color | Subtle / inner border |
| `border-accent` | border-color | Accent-colored border |
| `border-b-accent` | border-bottom-color | Active tab underline |
### Global UI tokens (used by `components/ui/` system)
| `bg-ui-bg` | `--color-ui-bg` |
| `bg-ui-bg-subtle` | `--color-ui-bg-subtle` |
| `bg-ui-bg-muted` | `--color-ui-bg-muted` |
| `border-ui-border` | `--color-ui-border` |
| `text-ui-text` | `--color-ui-text` |
| `text-ui-text-soft` | `--color-ui-text-soft` |
| `text-ui-text-muted` | `--color-ui-text-muted` |
### Brand tokens (fixed, same in all themes)
| `text-brand-orange` | `#ff5c00` |
| `bg-brand-orange` | `#ff5c00` |
| `text-brand-blue` | `#005b9a` |
| `bg-brand-blue` | `#005b9a` |
**How it works:** Declared Zebflow semantic names map to CSS variables. `bg-surface` becomes `background-color: var(--color-surface)`. The CSS defines `--color-surface` under the active theme and the browser resolves it automatically.
Arbitrary semantic names are deliberately not inferred because names such as `bg-fixed`, `border-collapse`, and `outline-offset-2` are real Tailwind utilities. For a project-specific variable, use an explicit arbitrary value:
```tsx
<div className="bg-[var(--color-product)] text-[var(--color-product-foreground)]" />
```
---
## `cx()` — Conditional Class Names
`cx()` is a global. Concatenates truthy class strings:
```tsx
// Simple conditional
<div className={cx("rounded p-4", isActive && "ring-2 ring-accent")}>
// Multi-variant composition
<button className={cx(
"px-4 py-2 rounded font-medium transition-colors",
variant === "primary" && "bg-accent text-white hover:bg-accent-strong",
variant === "ghost" && "hover:bg-surface-3 text-body",
variant === "danger" && "bg-red-600 text-white hover:bg-red-700",
size === "sm" && "text-sm px-3 py-1",
disabled && "opacity-50 cursor-not-allowed pointer-events-none",
)}>
```
---
## Dynamic Class Discovery (OXC Source Scanner)
The Tailwind compiler scans **all string and template literals** in the bundled page source
before generating CSS. This means classes in:
- `cx("a", condition ? "b" : "c")` — both branches discovered
- `const cls = "flex items-center"` — scanned at declaration
- `{_isOpen ? "block" : "hidden"}` — both string literals found
- Components that return `null` in SSR — their class strings still found
**`tw-variants` is only needed** when a class value is built entirely at runtime
from variables with no string literal form in source:
```tsx
// This would NOT be auto-discovered (pure runtime concatenation):
const prefix = userInput;
const cls = prefix + "-500"; // tw-variants needed if cls used as className
// This IS auto-discovered (string literals visible in source):
const cls = condition ? "bg-red-500" : "bg-blue-500"; // ✅ no tw-variants needed
```
---
## `tv()` — Variant Maps
`tailwind-variants` `tv()` is a global. For components with many permutations:
```tsx
const badge = tv({
base: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
variants: {
color: {
default: "bg-surface-3 text-body",
success: "bg-green-900/40 text-green-300",
warning: "bg-amber-900/40 text-amber-300",
danger: "bg-red-900/40 text-red-300",
accent: "bg-accent text-white",
},
size: {
sm: "text-[10px] px-1.5 py-0",
md: "text-xs px-2 py-0.5",
lg: "text-sm px-3 py-1",
},
},
defaultVariants: { color: "default", size: "md" },
});
// All variant strings are discovered automatically by the OXC source scanner
// No ghost span needed — the string literals in the tv() map are found statically
// Usage
<span className={badge({ color: "success", size: "sm" })}>Active</span>
<span className={badge({ color: "danger" })}>Error</span>
```
---
## Font tokens
```tsx
<h1 className="font-display text-2xl"> // "Pathway Extreme" display font
<p className="font-sans"> // "Roboto" body font
<code className="font-mono"> // "Roboto Mono"
```
---
## Rules
| Never `style=` | Use utility classes. Inline styles are a design system smell. |
| Never `[var(--studio-*)]` | Those old names are gone. Use semantic token classes: `bg-surface`, `text-body`, etc. |
| Never `[var(--zf-*)]` | Old prefix, gone. |
| `tw-variants` for pure runtime strings | Only needed when a class is assembled from user input or external data with no literal form in source. Auto-discovery handles all normal cases. |
| Prefer semantic tokens | `bg-surface` over `bg-[#111827]` — it adapts to dark/light theme automatically. |
| Arbitrary values OK when needed | `bg-[#ff5c00]`, `w-[320px]`, `mt-[3px]` are fine for one-offs. |