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
@propertyregistration and starts the variable inheriting. Pass a full@propertyobject 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
preflightis 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 resetand@layer baseare emitted before utilities. If you customize insertion or injection order (SSR, framework plugins), preserve@layerorder so globals are not overridden.