Skip to content

Installation

Terminal window
npm install csszyx

The csszyx umbrella package includes the compiler, runtime, types, and build plugin. The command-line tools (migrate, next, type generation) ship separately as @csszyx/cli — run them with npx @csszyx/cli <command> or install with pnpm add -D @csszyx/cli.

vite.config.ts
import { defineConfig } from 'vite';
import csszyx from 'csszyx/vite';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
// Order matters: csszyx → tailwindcss → react
...csszyx(),
tailwindcss(),
react(),
],
});
  1. Add @csszyx/runtime as a direct dependency. The transform injects a bare import { _szMerge } from '@csszyx/runtime', which a strict package manager (pnpm) does not resolve as a transitive dependency.

    Terminal window
    pnpm add @csszyx/runtime
  2. Wire the loader with the csszyxTurbopack() helper. It sets the *.tsx loader rule correctly (without as, which would otherwise self-match into ./X.tsx.tsx) and merges your existing turbopack config.

    next.config.mjs
    import { csszyxTurbopack } from '@csszyx/unplugin/next';
    export default {
    turbopack: csszyxTurbopack(
    {}, // your existing turbopack config (resolveAlias, other rules) is merged
    { safelistOutputFile: '.csszyx/next-loader-classes.html' },
    ),
    };
  3. Keep the Tailwind safelist fresh. Point @source at the safelist file and run the csszyx watcher/prebuild around Next:

    • dev: csszyx next watch (alongside next dev --turbopack)
    • build: csszyx next prebuild before next build --turbopack

CSSzyx requires Tailwind CSS v4. Create a CSS entry point:

src/index.css
@import "tailwindcss";

Import this in your app entry point:

src/main.tsx
import './index.css';
csszyx({
development: {
debug: true, // Enable debug logging
},
production: {
mangle: true, // Minify class names (z, y, x, ...)
injectChecksum: true, // Inject SSR hydration checksum
},
build: {
astBudgetLimit: 50_000, // Per-file AST node cap; throws past it
scanCss: 'src/index.css', // CSS file(s) to scan for @theme tokens
},
});

For per-element hydration recovery (szRecover="csr" / szRecover="dev-only") see SSR & Hydration → Recovery Tokens.

For SSR hydration safety, initialize the runtime in your app entry:

import { initRuntime } from '@csszyx/runtime';
initRuntime({
development: process.env.NODE_ENV === 'development',
strictHydration: true,
});

This is optional — CSSzyx works without it, but SSR hydration guards require it to be called before first render. Per-element CSR recovery is opted in via the szRecover JSX attribute on individual elements; see SSR & Hydration.

The sz prop comes from a JSX type augmentation in @csszyx/types. It is picked up automatically when you import from csszyx in a hoisting package manager. With a strict package manager (pnpm), or if your app uses sz without importing csszyx directly, add a one-line reference so TypeScript loads the augmentation.

  1. Install the types so the reference resolves at the top level:

    Terminal window
    pnpm add -D @csszyx/types
  2. Add a csszyx-env.d.ts at your project root (kept in your tsconfig.json include):

    /// <reference types="@csszyx/types/jsx" />

Then the sz prop is typed on every element:

// ✅ TypeScript knows this is valid
<div sz={{ p: 4, bg: 'blue-500', hover: { bg: 'blue-700' } }} />
// ❌ TypeScript error: 'red-999' is not a valid color
<div sz={{ bg: 'red-999' }} />

Classes not applying — make sure your CSS entry point uses the full Tailwind v4 bundle:

/* ✅ correct — includes theme + preflight + utilities */
@import "tailwindcss";
/* ❌ wrong — utilities only, theme variables undefined */
@import "tailwindcss/utilities";

Partial imports like tailwindcss/utilities only generate static-value utilities (.border-0, .m-px). Scale-dependent utilities like p-4, rounded-sm, text-xs require the theme layer (--spacing, --radius-sm, --text-xs) and will silently produce no CSS without it.

Monorepo with both Tailwind v3 and v4 — if your workspace has other packages that depend on Tailwind v3, your package’s CSS resolver may accidentally pick up v3 instead of v4, causing @import "tailwindcss" to fail or generate no theme utilities.

Fix: explicitly declare tailwindcss as a dependency in each package that uses CSSzyx:

{
"dependencies": {
"csszyx": "^0.4.0",
"tailwindcss": "^4.0.0"
}
}

Plugin order warnings — CSSzyx must be before Tailwind and React in the plugins array.

TypeScript errors with sz prop (Property 'sz' does not exist on type 'DetailedHTMLProps<...>') — the JSX augmentation is not loaded. Add @csszyx/types and a csszyx-env.d.ts with /// <reference types="@csszyx/types/jsx" />; see TypeScript above. This is common under pnpm and when csszyx is never imported directly.

Hydration warnings in Next.js — initialize the runtime in your root layout and opt in to per-element recovery with <section szRecover="csr">…</section> where mismatches are expected. See SSR & Hydration.

sz props not working in Astro MDX — the MDX Vite plugin compiles JSX to runtime calls before csszyx runs, so sz={{ ... }} props written directly in .mdx files are never transformed and render as sz="[object Object]".

Fix: put sz props in .tsx components and import them in MDX:

// src/components/MyDemo.tsx ← compiled by csszyx ✅
export function MyDemo() {
return <div sz={{ p: 4, bg: 'blue-500' }}>Hello</div>;
}
{/* src/pages/guide.mdx */}
import { MyDemo } from '../../components/MyDemo.tsx';
<MyDemo />