{"record":{"id":"b341f97ff0a71849","repo":"emotion-js/emotion","slug":"cx-can-only-be-used-during-render","errorCode":null,"errorMessage":"cx can only be used during render","messagePattern":"cx can only be used during render","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/class-names.tsx","lineNumber":157,"sourceCode":"export const ClassNames = /* #__PURE__ */ withEmotionCache<ClassNamesProps>(\n  (props, cache) => {\n    let hasRendered = false\n    let serializedArr: SerializedStyles[] = []\n\n    let css: ClassNamesContent['css'] = (...args) => {\n      if (hasRendered && isDevelopment) {\n        throw new Error('css can only be used during render')\n      }\n\n      let serialized = serializeStyles(args, cache.registered)\n      serializedArr.push(serialized)\n      // registration has to happen here as the result of this might get consumed by `cx`\n      registerStyles(cache, serialized, false)\n      return `${cache.key}-${serialized.name}`\n    }\n    let cx = (...args: Array<ClassNamesArg>) => {\n      if (hasRendered && isDevelopment) {\n        throw new Error('cx can only be used during render')\n      }\n      return merge(cache.registered, css, classnames(args))\n    }\n    let content = {\n      css,\n      cx,\n      theme: React.useContext(ThemeContext)\n    }\n    let ele = props.children(content)\n    hasRendered = true\n\n    return (\n      <>\n        <Insertion cache={cache} serializedArr={serializedArr} />\n        {ele}\n      </>\n    )\n  }","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/emotion-js/emotion/blob/b882bcba85132554992e4bd49e94c95939bbf810/packages/react/src/class-names.tsx#L139-L175","documentation":"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.","triggerScenarios":"Calling cx inside event handlers, useEffect/useLayoutEffect, setTimeout, or async callbacks after the ClassNames render has completed.","commonSituations":"Toggling classes on click via cx after mount; class composition in response to fetched data; storing cx in a ref/handler used later.","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"],"exampleFix":"// before\n<ClassNames>{({ cx }) => {\n  const onClick = () => el.className = cx('a', 'b')\n  return <div onClick={onClick} />\n}}</ClassNames>\n\n// after\n<ClassNames>{({ cx }) => {\n  const cls = cx('a', 'b')\n  return <div className={cls} />\n}}</ClassNames>","handlingStrategy":"validation","validationCode":"// compute merged classes during render only\nconst merged = cx('a', 'b') // inside render body\n// later: reuse `merged`, never call cx again","typeGuard":null,"tryCatchPattern":"try {\n  const cls = cxFn(args)\n} catch (e) {\n  if (e.message === 'cx can only be used during render') {\n    // fall back to plain className concatenation\n  } else throw e\n}","preventionTips":["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"],"tags":["react","class-names","render-phase","development"],"backgroundTag":"css-called-outside-render","analyzedSha":"b882bcba85132554992e4bd49e94c95939bbf810","analyzedAt":"2026-09-02T22:27:13.739Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}