Extending Presets
Use the extend keyword to add to what your presets provide instead of replacing it.
Every section of the config is either replaced or merged. Without extend, what you write is all Panda keeps:
panda.config.ts
export default defineConfig({
presets: ['@pandacss/preset-base', '@pandacss/preset-panda'],
theme: {
tokens: {
colors: { brand: { value: '#EA8433' } }
}
}
})
// tokens: brand. Every preset color is gone.With extend, your values deep-merge on top of what the presets provide:
panda.config.ts
export default defineConfig({
presets: ['@pandacss/preset-base', '@pandacss/preset-panda'],
theme: {
extend: {
tokens: {
colors: { brand: { value: '#EA8433' } }
}
}
}
})
// tokens: brand plus every preset color.extend works on theme, themes, conditions, utilities, patterns, globalCss, globalVars,
globalFontface, globalPositionTry, and staticCss. Recipes sit under theme, so they extend there too.
panda init scaffolds theme: { extend: {} } for you.
Add to a preset
Anything you put under extend is added. A new utility keeps every built-in one:
panda.config.ts
export default defineConfig({
utilities: {
extend: {
br: {
className: 'rounded',
values: 'radii',
transform: value => ({ borderRadius: value })
}
}
}
})Override part of a preset
The merge is deep, so you can change one field of something a preset defines and keep the rest. This renames the
class the br utility emits and leaves its values and transform alone:
panda.config.ts
export default defineConfig({
presets: ['@acme/preset'],
utilities: {
extend: {
br: { className: 'br' }
}
}
})Remove something from a preset
extend only adds, so removing takes a plugin. config:resolved runs after every preset has merged:
panda.config.ts
import { defineConfig, definePlugin } from '@pandacss/dev'
const removeStack = definePlugin({
name: 'remove-stack',
hooks: {
'config:resolved': ({ config, utils }) => utils.omit(config, ['patterns.stack'])
}
})
export default defineConfig({
presets: ['@pandacss/preset-base', '@pandacss/preset-panda'],
plugins: [removeStack]
})For a whole section, drop the preset and spread back only the parts you want:
panda.config.ts
import base from '@pandacss/preset-base'
const { stack, ...patterns } = base.patterns
export default defineConfig({
presets: ['@pandacss/preset-panda'],
patterns: { extend: patterns }
})To start with nothing at all, see Minimal setup.
Common mistakes
Forgetting extend. The symptom is every preset token or utility disappearing at once.
// ❌ replaces every color
theme: { tokens: { colors: { brand: { value: '#EA8433' } } } }
// ✅ adds brand to the palette
theme: { extend: { tokens: { colors: { brand: { value: '#EA8433' } } } } }Skipping the category. Tokens live under tokens or semanticTokens, not directly under extend.
// ❌ ignored
theme: { extend: { colors: { brand: { value: '#EA8433' } } } }
// ✅
theme: { extend: { tokens: { colors: { brand: { value: '#EA8433' } } } } }Putting extend at the root. It belongs inside each section.
// ❌ not a config key
extend: { theme: { tokens: {} } }
// ✅
theme: { extend: { tokens: {} } }Expecting a later preset to merge on its own. Presets apply in order and your config applies last, but a preset
without extend replaces the sections it defines, exactly like your config would. Author presets with extend when
they build on another preset. See Presets.