Skip to content

[Compiler]: React Compiler should error on document.getElementById call during render #31932

Open
@rishitells

Description

@rishitells

What kind of issue is this?

  • React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization)
  • babel-plugin-react-compiler (build issue installing or using the Babel plugin)
  • eslint-plugin-react-compiler (build issue installing or using the eslint plugin)
  • react-compiler-healthcheck (build issue installing or using the healthcheck script)

Link to repro

https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAIngIYA2EA5gOp44AWAChDDlQBTBF5gB5AA4JiAXwCURYAB1iROITA4FhTnkwIYRALxEcATxEQ0RACYQ4UALaiVAQh16ZILGYRoNCMy6IB+c0sbOwA6GgQcAFFKBFtMHAAhAwBJMy4AciF2TkoAWhgICBx0qWQiTChKSgBuOSIiGAjYYi46+qIAHjIqWiIIEUwdYH5hUTEAPjb2zu7qGhC2DipVePIvGCHFVfWJqemZijmQgGE1O3GACQQqiA6AelnaE7P4yflp+8f5xZy3j4fDrQ-kQJLVMGIQGIgA

Repro steps

Steps to reproduce

  1. Create a simple dialog component that uses Portal with a dynamic container:
function DialogWithPortal({ isOpen }) {
  const container = typeof document !== "undefined" ? document.getElementById('portal-root') : null;
  return (
    <Dialog open={isOpen}>
      <Dialog.Portal container={container}>
        <Dialog.Content>Hello</Dialog.Content>
      </Dialog.Portal>
    </Dialog>
  );
}
  1. Mount the component when portal container exists in DOM:
// DOM has: <div id="portal-root"></div>
<DialogWithPortal isOpen={true} />
  1. Observe that dialog doesn't open because compiler memoizes initial null container value

Expected behavior:

  • document.getElementById() should be evaluated on each render to find the portal container

Actual behaviour:

  • Compiler memoizes the initial document.getElementById() call
  • If container doesn't exist on first render, null is cached permanently
  • Subsequent renders use cached null value even after container is added to DOM

The issue is in how the compiler transforms the code:

// Initial DOM query is memoized and never rechecked
  let t1;
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
    t1 =
      typeof document !== "undefined"
        ? document.getElementById("portal-root")
        : null;
    $[0] = t1;
  } else {
    t1 = $[0];
  }
  const container = t1;

How often does this bug happen?

Every time

What version of React are you using?

^18.2.0

What version of React Compiler are you using?

19.0.0-beta-201e55d-20241215

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions