emotion-js/emotion · error · Error
cx can only be used during render
Error message
cx can only be used during render
What it means
Like css(), the cx() helper from the ClassNames render prop is only valid during render. After the component has rendered, invoking cx() in development throws, since merging registered class names must happen while emotion can still attach the result to the rendered output.
Source
Thrown at packages/react/src/class-names.tsx:157
export const ClassNames = /* #__PURE__ */ withEmotionCache<ClassNamesProps>(
(props, cache) => {
let hasRendered = false
let serializedArr: SerializedStyles[] = []
let css: ClassNamesContent['css'] = (...args) => {
if (hasRendered && isDevelopment) {
throw new Error('css can only be used during render')
}
let serialized = serializeStyles(args, cache.registered)
serializedArr.push(serialized)
// registration has to happen here as the result of this might get consumed by `cx`
registerStyles(cache, serialized, false)
return `${cache.key}-${serialized.name}`
}
let cx = (...args: Array<ClassNamesArg>) => {
if (hasRendered && isDevelopment) {
throw new Error('cx can only be used during render')
}
return merge(cache.registered, css, classnames(args))
}
let content = {
css,
cx,
theme: React.useContext(ThemeContext)
}
let ele = props.children(content)
hasRendered = true
return (
<>
<Insertion cache={cache} serializedArr={serializedArr} />
{ele}
</>
)
}View on GitHub (pinned to b882bcba85)
Solutions
- Call cx only inside the render-prop body during render
- Compute the merged class string during render and reuse the string in handlers/effects
- Use document/classList or state-driven class switching outside render instead of cx
- Restructure so conditional class logic is derived during render from state/props
Example fix
// before
<ClassNames>{({ cx }) => {
const onClick = () => el.className = cx('a', 'b')
return <div onClick={onClick} />
}}</ClassNames>
// after
<ClassNames>{({ cx }) => {
const cls = cx('a', 'b')
return <div className={cls} />
}}</ClassNames> Defensive patterns
Strategy: validation
Validate before calling
// compute merged classes during render only
const merged = cx('a', 'b') // inside render body
// later: reuse `merged`, never call cx again Try / catch
try {
const cls = cxFn(args)
} catch (e) {
if (e.message === 'cx can only be used during render') {
// fall back to plain className concatenation
} else throw e
} Prevention
- Never store cx in refs or pass it into effects/handlers
- Derive conditional classes from state during render
- Use template strings with precomputed class names outside render
When it happens
Trigger: Calling cx inside event handlers, useEffect/useLayoutEffect, setTimeout, or async callbacks after the ClassNames render has completed.
Common situations: Toggling classes on click via cx after mount; class composition in response to fetched data; storing cx in a ref/handler used later.
Related errors
- css can only be used during render
- Strings are not allowed as css prop values, please wrap it i
- noComponentSelectorMessage
- [ThemeProvider] Please return an object from your theme func
- [ThemeProvider] Please make your theme prop a plain object
AI-assisted analysis of emotion-js/emotion@b882bcba85 (2026-09-02).
Data as JSON: /api/errors/b341f97ff0a71849.
Report an issue: GitHub.