Want to skip the docs? Check out pandamastery.com - the best way to learn Panda CSS

styling
global styles

Global Styles

How to work with resets, global styles, and global CSS variables in Panda.

Panda groups global styles into reset and base layers so you can control defaults predictably and override them safely.

Layers overview

  • @layer reset: Preflight/reset styles, enabled with preflight.
  • @layer base: Your additional global styles via globalCss.
💡

See also: Cascade layers

Reset (preflight)

Enable or scope the reset styles.

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  preflight: true
})

Scope and level:

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  preflight: { scope: '.extension', level: 'element' }
})

Exposed global CSS variables

These variables are used by the reset and defaults. Set them in globalCss:

  • --global-font-body
  • --global-font-mono
  • --global-color-border
  • --global-color-placeholder
  • --global-color-selection
  • --global-color-focus-ring

Setting global styles (base)

Use globalCss to define additional global styles and set variables.

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  // ...
  globalCss: {
    html: {
      '--global-font-body': 'Inter, sans-serif',
      '--global-font-mono': 'Mononoki Nerd Font, monospace',
      '--global-color-border': 'colors.gray.400',
      '--global-color-placeholder': 'rgba(0,0,0,0.5)',
      '--global-color-selection': 'rgba(0,115,255,0.3)',
      '--global-color-focus-ring': 'colors.blue.400'
    }
  }
})

Theming patterns

You can set variables on :root, a .dark class, or via media queries.

:root {
  --global-color-border: oklch(0.8 0 0);
}
.dark {
  --global-color-border: oklch(0.72 0 0);
}
 
@media (prefers-color-scheme: dark) {
  :root {
    --global-color-border: oklch(0.72 0 0);
  }
}

Custom global variables (globalVars)

Define additional global CSS variables or @property entries.

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  globalVars: {
    '--button-color': {
      syntax: '<color>',
      inherits: false,
      initialValue: 'blue'
    }
  }
})
💡

Keys from globalVars are suggestable in style objects and generated near your tokens at cssVarRoot.

Variables owned by a utility

A utility that writes a CSS variable declares the registration itself, so the two can't drift apart:

panda.config.ts

export default defineConfig({
  utilities: {
    blur: {
      className: 'blur',
      globalVars: {
        '--blur': { syntax: '*', inherits: false }
      },
      transform: (value) => ({ '--blur': `blur(${value})` })
    }
  }
})

Only the utility that writes the variable needs to declare it. A second utility that reads it — filter: 'auto' composing var(--blur, ) — declares nothing.

These merge into globalVars, and Panda drops any registration your stylesheet never references. Declaring one costs nothing until it's used, which is how preset-base registers dozens of them without charging projects that don't mask, transform, or filter.

Two rules keep collisions honest:

  • Two utilities registering the same name with different definitions is a config error. A CSS variable has one registration for the whole document, so share one definition between them.
  • Putting a plain value on a name a utility registered warns, because the value drops the @property registration and starts the variable inheriting. Pass a full @property object if you meant to retune it. The warning only appears when your stylesheet actually reads that variable, so reusing a name the preset happens to reserve is fine as long as the two never meet.

Older browsers

@property needs Chrome 85+, Safari 16.4+, or Firefox 128+. Engines without it skip the registration entirely, so a declaration that reads an unregistered variable is dropped — the utility silently does nothing.

Set optimize.propertyFallback to also seed the defaults as plain declarations:

panda.config.ts

export default defineConfig({
  optimize: { propertyFallback: true }
})

Panda derives the seeds from the registrations it actually emitted, so you only pay for the variables your project uses. Modern engines ignore them.

Troubleshooting

  • Global styles aren't applied: Confirm preflight is enabled (if you expect reset), and ensure your selector (html, :root, .dark, etc.) matches the element where variables are set.

  • Global styles are overridden by utilities or component styles: Verify layer order and specificity. Ensure @layer reset and @layer base are emitted before utilities. If you customize insertion or injection order (SSR, framework plugins), preserve @layer order so globals are not overridden.