Installation
Install
Section titled “Install”npm install csszyxpnpm add csszyxyarn add csszyxThe 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.
Setup by Platform
Section titled “Setup by Platform”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(), ],});import type { NextConfig } from 'next';
const nextConfig: NextConfig = { reactStrictMode: true, webpack: (config) => { const csszyxWebpack = require('@csszyx/unplugin/webpack').default; config.plugins.push(csszyxWebpack()); return config; },};
export default nextConfig;const csszyxWebpack = require('@csszyx/unplugin/webpack').default;
module.exports = { plugins: [ csszyxWebpack(), // ... other plugins ],};Next.js Turbopack setup
Section titled “Next.js Turbopack setup”-
Add
@csszyx/runtimeas a direct dependency. The transform injects a bareimport { _szMerge } from '@csszyx/runtime', which a strict package manager (pnpm) does not resolve as a transitive dependency.Terminal window pnpm add @csszyx/runtime -
Wire the loader with the
csszyxTurbopack()helper. It sets the*.tsxloader rule correctly (withoutas, which would otherwise self-match into./X.tsx.tsx) and merges your existingturbopackconfig.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' },),}; -
Keep the Tailwind safelist fresh. Point
@sourceat the safelist file and run the csszyx watcher/prebuild around Next:- dev:
csszyx next watch(alongsidenext dev --turbopack) - build:
csszyx next prebuildbeforenext build --turbopack
- dev:
Tailwind CSS v4 Entry Point
Section titled “Tailwind CSS v4 Entry Point”CSSzyx requires Tailwind CSS v4. Create a CSS entry point:
@import "tailwindcss";Import this in your app entry point:
import './index.css';Plugin Options
Section titled “Plugin Options”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.
Optional: Initialize Runtime
Section titled “Optional: Initialize Runtime”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.
TypeScript
Section titled “TypeScript”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.
-
Install the types so the reference resolves at the top level:
Terminal window pnpm add -D @csszyx/types -
Add a
csszyx-env.d.tsat your project root (kept in yourtsconfig.jsoninclude):/// <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' }} />Troubleshooting
Section titled “Troubleshooting”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 />