Skip to content

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

Theme

Tokens

Define design tokens, reference them from each other, and use them in your styles.

A design token is a named value: brand instead of #EA8433, body instead of a font stack. You define them once in the config, and every style reads them by name. Panda's token format follows the W3C Design Tokens (opens in a new tab) spec.

Each token is an object with a value, and optionally a description:

danger: {
  value: '#EE0F0F',
  description: 'Color for errors'
}

Core tokens

Core tokens are raw values. They live under theme.tokens, grouped by category:

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  theme: {
    extend: {
      tokens: {
        colors: {
          red: { value: '#EE0F0F' },
          green: { value: '#0FEE0F' }
        },
        fonts: {
          body: { value: 'system-ui, sans-serif' }
        }
      }
    }
  }
})

Use them by name wherever a style property takes that category:

css({ color: 'red', fontFamily: 'body' })

Reference a token

A token value can point at another token with {path.to.token}. Panda resolves it to that token's CSS variable, so the two stay in sync:

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  theme: {
    extend: {
      tokens: {
        colors: {
          brand: { value: '{colors.red.500}' }
        },
        borders: {
          subtle: { value: '1px solid {colors.gray.200}' }
        }
      }
    }
  }
})

References work inside any token value, including composite ones like borders and shadows. Semantic tokens, next, are built entirely on them.

Semantic tokens

A semantic token names a role, and its value references a core token. Components use the role, so a redesign changes one config line instead of every call site. They live under theme.semanticTokens:

panda.config.ts

export default defineConfig({
  theme: {
    extend: {
      semanticTokens: {
        colors: {
          danger: { value: '{colors.red}' },
          success: { value: '{colors.green}' }
        }
      }
    }
  }
})

The value can change per condition. This is how light and dark mode work:

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  theme: {
    extend: {
      semanticTokens: {
        colors: {
          danger: { value: { base: '{colors.red}', _dark: '{colors.darkred}' } }
        }
      }
    }
  }
})

Only at-rule and parent-selector conditions can be used here. For whole alternative palettes, see Multiple Themes.

Nesting

Group related tokens under one key. DEFAULT gives the group itself a value:

panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  theme: {
    extend: {
      semanticTokens: {
        colors: {
          bg: {
            DEFAULT: { value: '{colors.gray.50}' },
            muted: { value: '{colors.gray.100}' }
          }
        }
      }
    }
  }
})
css({ bg: 'bg', color: 'bg.muted' })

Generated CSS

Every token becomes a CSS variable, named from its path. Semantic tokens with conditions get one declaration per condition:

:where(:root, :host) {
  --colors-red: #ee0f0f;
  --colors-danger: var(--colors-red);
}
.dark {
  --colors-danger: var(--colors-darkred);
}

cssVarRoot in the config sets the selector the variables are declared on. The default is :where(:root, :host).

Use a token

In styles

In a style property, by name:

css({
  color: 'danger',
  fontFamily: 'body'
})

Inside a longer value, with the same {path.to.token} reference:

css({
  border: '1px solid {colors.danger}',
  boxShadow: '0 1px 2px {colors.gray.900}'
})

token() does the same and takes a fallback for when the token might not exist:

css({
  border: '1px solid token(colors.danger, crimson)'
})

Both work in at-rules:

css({
  '@media (min-width: {sizes.4xl})': {
    color: 'danger'
  }
})

From JavaScript

The generated helpers read tokens at runtime. token() returns the value and token.var() returns the CSS variable:

import { token } from '../styled-system/tokens'
 
<div
  style={{
    background: token('colors.danger'),
    borderColor: token.var('colors.gray.200')
  }}
/>

Reach for these only when a style object can't express it, like an inline style or a third-party API that wants a raw value. The forms above are extracted at build time and cost nothing at runtime. See tokens/ for the helpers.

See also

Edit this page on GitHubView as markdown
Last updated on