Skip to content

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.

ts
// 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.

ts
// 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
})
ts
// ❌ 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.

When you think you need runtime style logic, pick one of these patterns first:

  1. Predeclare variants and switch class names at runtime.
  2. Move repeated combinations into shortcuts.
  3. Move theme values or per-instance dynamic values into CSS variables.
  4. Move state differences into selectors such as hover, focus, or custom aliases.
  5. 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.

ts
// ✅ 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

DoDo 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.

Next