Skip to content

Fix: Panda CSS Not Working — Styles Not Applying, Tokens Not Resolving, or Build Errors

FixDevs ·

Quick Answer

How to fix Panda CSS issues — PostCSS setup, panda.config.ts token system, recipe and pattern definitions, conditional styles, responsive design, and integration with Next.js and Vite.

The Problem

You write Panda CSS styles but nothing appears:

import { css } from '../styled-system/css';

function Button() {
  return (
    <button className={css({ bg: 'blue.500', color: 'white', p: '4' })}>
      Click me
    </button>
  );
}
// Button renders with no styles — plain unstyled HTML

Or a token value doesn’t resolve:

css({ color: 'primary' })
// TypeScript error: Type '"primary"' is not assignable to type...

Or the build fails:

Error: Cannot find module '../styled-system/css'

Why This Happens

Panda CSS is a build-time CSS-in-JS library. It scans your source files at build time, extracts style function calls, and generates a static CSS file. No runtime JavaScript:

  • The styled-system directory must be generated first — running npx panda codegen creates the styled-system/ directory with css, cva, sva, and other utilities. Without this step, imports fail. The codegen must re-run whenever you change panda.config.ts.
  • Panda scans specific file paths — the include array in panda.config.ts tells Panda which files to scan for style usage. Files outside this glob pattern are invisible to Panda, and their styles won’t appear in the generated CSS.
  • Token values must exist in the themecolor: 'blue.500' works because blue.500 is a default token. color: 'primary' only works if you define primary in the theme.tokens or theme.semanticTokens config. Unrecognized values cause type errors.
  • Generated CSS must be imported — Panda generates a CSS file that you must import in your app’s entry point. Without this import, the generated styles exist but aren’t loaded.

Fix 1: Set Up Panda CSS

npm install -D @pandacss/dev
npx panda init
// panda.config.ts
import { defineConfig } from '@pandacss/dev';

export default defineConfig({
  // Enable CSS reset
  preflight: true,

  // Files to scan for styles
  include: [
    './src/**/*.{ts,tsx,js,jsx}',
    './app/**/*.{ts,tsx,js,jsx}',      // Next.js App Router
    './pages/**/*.{ts,tsx,js,jsx}',    // Next.js Pages Router
    './components/**/*.{ts,tsx,js,jsx}',
  ],

  // Files to exclude
  exclude: [],

  // Theme customization
  theme: {
    extend: {
      tokens: {
        colors: {
          primary: { value: '#3b82f6' },
          secondary: { value: '#64748b' },
        },
        fonts: {
          body: { value: 'Inter, sans-serif' },
          heading: { value: 'Cal Sans, sans-serif' },
        },
      },
      semanticTokens: {
        colors: {
          // Tokens that change with color mode
          text: {
            value: { base: '{colors.gray.900}', _dark: '{colors.gray.100}' },
          },
          bg: {
            value: { base: 'white', _dark: '{colors.gray.900}' },
          },
          accent: {
            value: { base: '{colors.primary}', _dark: '{colors.blue.400}' },
          },
        },
      },
    },
  },

  // Output directory for generated code
  outdir: 'styled-system',

  // JSX framework
  jsxFramework: 'react',  // 'react' | 'solid' | 'vue' | 'qwik'
});
# Generate the styled-system directory
npx panda codegen

# Add to package.json scripts
# "prepare": "panda codegen"
// postcss.config.mjs — required
export default {
  plugins: {
    '@pandacss/dev/postcss': {},
  },
};
/* src/index.css or app/globals.css — import generated styles */
@layer reset, base, tokens, recipes, utilities;
// Import CSS in your entry point
// app/layout.tsx (Next.js) or src/main.tsx (Vite)
import './globals.css';

Fix 2: Use the css() Function and Utilities

import { css } from '../styled-system/css';
import { flex, center, stack, grid } from '../styled-system/patterns';

// Basic styles
function Card() {
  return (
    <div
      className={css({
        bg: 'white',
        borderRadius: 'lg',
        boxShadow: 'md',
        p: '6',
        // Shorthand properties
        mx: 'auto',        // marginInline
        mt: '4',            // marginTop
        w: 'full',          // width
        maxW: 'lg',         // maxWidth
      })}
    >
      <h2 className={css({
        fontSize: '2xl',
        fontWeight: 'bold',
        color: 'gray.900',
        mb: '2',
      })}>
        Card Title
      </h2>
      <p className={css({ color: 'gray.600', lineHeight: 'relaxed' })}>
        Card content here.
      </p>
    </div>
  );
}

// Responsive styles — mobile-first breakpoints
function ResponsiveLayout() {
  return (
    <div
      className={css({
        display: 'flex',
        flexDirection: 'column',
        gap: '4',
        // Responsive: sm, md, lg, xl, 2xl
        md: {
          flexDirection: 'row',
          gap: '8',
        },
        lg: {
          maxW: '6xl',
          mx: 'auto',
        },
      })}
    >
      <aside className={css({ w: { base: 'full', md: '1/4' } })}>Sidebar</aside>
      <main className={css({ w: { base: 'full', md: '3/4' } })}>Content</main>
    </div>
  );
}

// Patterns — pre-built layout utilities
function PatternExamples() {
  return (
    <>
      {/* Flex layout */}
      <div className={flex({ gap: '4', align: 'center', justify: 'between' })}>
        <span>Left</span>
        <span>Right</span>
      </div>

      {/* Center content */}
      <div className={center({ h: '64' })}>
        <p>Centered vertically and horizontally</p>
      </div>

      {/* Stack (vertical flex) */}
      <div className={stack({ gap: '4', direction: 'column' })}>
        <div>Item 1</div>
        <div>Item 2</div>
      </div>

      {/* Grid */}
      <div className={grid({ columns: { base: 1, md: 2, lg: 3 }, gap: '6' })}>
        <div>Cell 1</div>
        <div>Cell 2</div>
        <div>Cell 3</div>
      </div>
    </>
  );
}

Fix 3: Recipes — Reusable Component Variants

// styled-system recipes (defined in panda.config.ts)
// panda.config.ts
import { defineConfig } from '@pandacss/dev';

export default defineConfig({
  theme: {
    extend: {
      recipes: {
        button: {
          className: 'button',
          description: 'Button component styles',
          base: {
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            borderRadius: 'md',
            fontWeight: 'semibold',
            cursor: 'pointer',
            transition: 'all 0.2s',
            _disabled: {
              opacity: '0.5',
              cursor: 'not-allowed',
            },
          },
          variants: {
            variant: {
              solid: {
                bg: 'primary',
                color: 'white',
                _hover: { bg: 'blue.600' },
              },
              outline: {
                border: '2px solid',
                borderColor: 'primary',
                color: 'primary',
                _hover: { bg: 'blue.50' },
              },
              ghost: {
                color: 'primary',
                _hover: { bg: 'blue.50' },
              },
            },
            size: {
              sm: { px: '3', py: '1.5', fontSize: 'sm' },
              md: { px: '4', py: '2', fontSize: 'md' },
              lg: { px: '6', py: '3', fontSize: 'lg' },
            },
          },
          defaultVariants: {
            variant: 'solid',
            size: 'md',
          },
        },
      },
    },
  },
});
// Usage after running npx panda codegen
import { button } from '../styled-system/recipes';

function Button({ variant, size, children, ...props }) {
  return (
    <button className={button({ variant, size })} {...props}>
      {children}
    </button>
  );
}

// Or use cva() for inline recipe definitions
import { cva } from '../styled-system/css';

const badge = cva({
  base: {
    px: '2',
    py: '0.5',
    borderRadius: 'full',
    fontSize: 'xs',
    fontWeight: 'bold',
  },
  variants: {
    status: {
      success: { bg: 'green.100', color: 'green.800' },
      warning: { bg: 'yellow.100', color: 'yellow.800' },
      error: { bg: 'red.100', color: 'red.800' },
    },
  },
});

<span className={badge({ status: 'success' })}>Active</span>

Fix 4: Conditional and Dynamic Styles

import { css, cx } from '../styled-system/css';

// Conditional styles — use conditions (pseudo-classes, states)
function InteractiveCard() {
  return (
    <div
      className={css({
        bg: 'white',
        p: '4',
        borderRadius: 'lg',
        border: '1px solid',
        borderColor: 'gray.200',
        transition: 'all 0.2s',
        // Hover state
        _hover: {
          borderColor: 'primary',
          boxShadow: 'lg',
          transform: 'translateY(-2px)',
        },
        // Focus-within (when child is focused)
        _focusWithin: {
          borderColor: 'primary',
          ring: '2',
          ringColor: 'blue.200',
        },
        // Dark mode
        _dark: {
          bg: 'gray.800',
          borderColor: 'gray.700',
        },
        // First/last child
        _first: { mt: '0' },
        _last: { mb: '0' },
      })}
    >
      Interactive card
    </div>
  );
}

// Dynamic styles based on props
function Alert({ type }: { type: 'info' | 'warning' | 'error' }) {
  return (
    <div
      className={css({
        p: '4',
        borderRadius: 'md',
        // Dynamic value based on prop
        bg: type === 'info' ? 'blue.50' : type === 'warning' ? 'yellow.50' : 'red.50',
        color: type === 'info' ? 'blue.800' : type === 'warning' ? 'yellow.800' : 'red.800',
        borderLeft: '4px solid',
        borderColor: type === 'info' ? 'blue.400' : type === 'warning' ? 'yellow.400' : 'red.400',
      })}
    >
      Alert content
    </div>
  );
}

// Merging class names — use cx()
function MergedStyles({ className }: { className?: string }) {
  return (
    <div className={cx(
      css({ bg: 'white', p: '4' }),
      css({ borderRadius: 'lg' }),
      className,  // External classes merge correctly
    )}>
      Merged styles
    </div>
  );
}

Fix 5: JSX Style Props (Type-Safe)

Panda generates typed JSX components for style props:

// panda.config.ts — enable JSX
export default defineConfig({
  jsxFramework: 'react',
  jsxStyleProps: 'all',  // Enable style props on JSX components
});
// After codegen — use styled components
import { styled } from '../styled-system/jsx';
import { flex, center } from '../styled-system/patterns';

// styled.div — type-safe style props
function StyledExample() {
  return (
    <styled.div bg="white" p="6" borderRadius="lg" shadow="md">
      <styled.h1 fontSize="2xl" fontWeight="bold" mb="4">
        Title
      </styled.h1>
      <styled.p color="gray.600" lineHeight="relaxed">
        Paragraph with style props.
      </styled.p>
    </styled.div>
  );
}

// Pattern JSX components
import { Flex, Center, Stack, Grid } from '../styled-system/jsx';

function LayoutExample() {
  return (
    <Stack gap="4">
      <Flex justify="between" align="center">
        <styled.span fontWeight="bold">Title</styled.span>
        <styled.button bg="primary" color="white" px="4" py="2" borderRadius="md">
          Action
        </styled.button>
      </Flex>
      <Grid columns={{ base: 1, md: 3 }} gap="6">
        <styled.div p="4" bg="gray.50" borderRadius="md">Cell 1</styled.div>
        <styled.div p="4" bg="gray.50" borderRadius="md">Cell 2</styled.div>
        <styled.div p="4" bg="gray.50" borderRadius="md">Cell 3</styled.div>
      </Grid>
    </Stack>
  );
}

Fix 6: Integration with Next.js and Vite

Next.js App Router:

// postcss.config.mjs
export default {
  plugins: {
    '@pandacss/dev/postcss': {},
  },
};
// app/layout.tsx
import '../styled-system/styles.css';
// Or if using a custom global CSS file:
// import './globals.css';  // which contains @layer reset, base, tokens, recipes, utilities;

export default function RootLayout({ children }) {
  return <html><body>{children}</body></html>;
}

Vite:

// postcss.config.mjs — same PostCSS config
export default {
  plugins: {
    '@pandacss/dev/postcss': {},
  },
};
// src/main.tsx
import '../styled-system/styles.css';
// Or: import './index.css';
// package.json — auto-generate on dev/build
{
  "scripts": {
    "prepare": "panda codegen",
    "dev": "panda codegen && vite",
    "build": "panda codegen && vite build"
  }
}

Still Not Working?

Styles appear in dev but not in production — the CSS file might not be included in the production build. Verify the @layer import is in your CSS entry point and that it’s imported in your app. Also run npx panda codegen before building — some CI environments skip the prepare script.

TypeScript can’t find styled-system imports — add the path to your tsconfig.json: "paths": { "styled-system/*": ["./styled-system/*"] }. Also ensure styled-system/ is not in .gitignore (or add it and run codegen in CI).

Dynamic values don’t work — Panda is build-time, not runtime. css({ color: someVariable }) where someVariable is computed at runtime won’t work because Panda can’t scan dynamic values. Use conditional objects or recipes for variant-based styling. For truly dynamic values (e.g., user-selected color), use inline style attribute.

Hot reload doesn’t pick up new tokens — changes to panda.config.ts require running npx panda codegen to regenerate the styled-system/ directory. The PostCSS plugin watches for style changes in components but doesn’t watch config changes.

For related CSS issues, see Fix: Tailwind CSS Not Working and Fix: styled-components Not Working.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles