Static Arguments
This is the most important constraint in PikaCSS.
pika() is evaluated from source code at build time. That means the integration needs to understand the argument shape without running your application. If the style input depends on runtime state, PikaCSS cannot reliably transform it.
What is safe
Literal objects, arrays, strings, nested literal structures, and stable composition are the happy path.
// pika() is available as a global function — no import needed
// ✅ Static object literal — works perfectly
const btn = pika({
backgroundColor: 'blue',
color: 'white',
padding: '8px 16px',
})What is not safe
Runtime function calls, mutable state, computed member access, or arbitrary expressions inside pika() break the build-time model.
// pika() is available as a global function — no import needed
// ❌ Runtime variable — cannot be evaluated at build time
const userColor = getUserPreference()
const btn = pika({
backgroundColor: userColor, // Error: userColor is not statically analyzable
})// ❌ Invalid: Variable reference
const color = 'red'
pika({ color: color })
// ❌ Invalid: Variable as argument
const styles = { color: 'red' }
pika(styles)
// ❌ Invalid: Function call in value
pika({ color: getColor() })
// ❌ Invalid: Template literal with expression
const size = 16
pika({ fontSize: `${size}px` })
// ❌ Invalid: Spread of variable
const base = { color: 'red' }
pika({ ...base })
// ❌ Invalid: Conditional expression
const isDark = true
pika({ color: isDark ? 'white' : 'black' })
// ❌ Invalid: Binary expression
const x = 10
pika({ width: x + 'px' })
// ❌ Invalid: Member expression
const theme = { color: 'red' }
pika({ color: theme.color })
// ❌ Invalid: Dynamic computed key
const key = 'color'
pika({ [key]: 'red' })Why this limitation exists
PikaCSS gets its value from this boundary:
- It can transform source into deterministic atomic CSS.
- It can deduplicate declarations because it knows the style content up front.
- It can generate autocomplete types and plugin-defined tokens.
- It keeps runtime bundles free of styling work.
If the engine accepted arbitrary runtime values, those guarantees would collapse.
Recommended alternatives
When you think you need runtime style logic, pick one of these patterns first:
- Predeclare variants and switch class names at runtime.
- Move repeated combinations into shortcuts.
- Move theme values or per-instance dynamic values into CSS variables.
- Move state differences into selectors such as
hover,focus, or custom aliases. - Compute which static style block to use, not the contents of the block itself.
A good mental model
Choose between static style definitions at runtime. Do not compute style definitions at runtime.
If the value itself still has to change at runtime, read Dynamic Values With CSS Variables.
Enforce the rule early
Use the ESLint integration so mistakes are caught in editor and CI instead of only during build output inspection.
// ✅ Valid: Static literal arguments
pika({ color: 'red' })
// ✅ Valid: Multiple static arguments
pika({ color: 'red' }, { fontSize: '16px' })
// ✅ Valid: Nested static objects (pseudo-classes, media queries)
pika({ color: 'black', '&:hover': { color: 'blue' } })
// ✅ Valid: Number values
pika({ fontSize: 16, zIndex: -1 })
// ✅ Valid: Template literal without expressions
pika({ color: `red` })
// ✅ Valid: Spread of static object literal
pika({ ...{ color: 'red' } })
// ✅ Valid: Using variants
pika.str({ color: 'red' })
pika.arr({ display: 'flex' })
pikap({ margin: '10px' })Do and do not
| Do | Do not |
|---|---|
Predeclare a primary, secondary, and danger style variant. | Build a style object from API data inside pika(). |
| Use CSS variables for theme values. | Read a runtime theme object directly from the call. |
| Use selectors and shortcuts to encode recurring patterns. | Rebuild the same logic with ad hoc computed objects in each component. |