Skip to content

Incorrect window reference when used in a new browser window #863

@lfpose

Description

@lfpose

When using this component inside a new window (e.g., via window.open), there are issues related to resizing.

Root Cause
The component currently references the global window object directly. This always points to the main window, not the newly opened one. As a result, event listeners (e.g., for resize) do not behave correctly when the component is rendered in a different window context.

Proposed Solution
Allow the component to accept a window prop, enabling consumers to specify which window object the component should use. This would ensure the correct event context is used, especially for resize or similar interactions.

Additional Notes
JavaScript execution still runs in the main thread of the original window, but referencing window in code always points to the main window unless explicitly overridden.

Reproduction:

https://codesandbox.io/p/sandbox/zw8dzr

Code in case sandbox stops working

import "./styles.css";
import { Allotment } from "allotment";
import "allotment/dist/style.css";
import {
  useState,
  useMemo,
  useEffect,
  PropsWithChildren,
  FC,
  useLayoutEffect,
} from "react";
import { createPortal } from "react-dom";

function App() {
  const [newWindow, setNewWindow] = useState<Window | null>(null);
  const open = () => {
    const newWindow = window.open(
      "about:blank",
      "_blank",
      `width=1280,height=720`
    );
    setNewWindow(newWindow);
    console.log("new window", newWindow);
  };

  return (
    <div>
      This allotment component is in the main window. It works well. Try
      resizing.
      <Content />
      <br />
      Open the link to test in a new window. Note: you might need to open this
      codesandbox in its own window for styles to load correctly.
      <br />
      Click top right icon button "Open in a new tab"
      <br />
      <button onClick={open}>Open</button>
      {newWindow && (
        <NewWindow newWindow={newWindow}>
          Here the allotmenet component does NOT work well. Because the "window"
          object used within the component is not the right one.
          <Content />
        </NewWindow>
      )}
    </div>
  );
}

const Content = () => {
  return (
    <div style={{ border: "1px dotted red", height: "200px" }}>
      <Allotment>
        <div>Pane 1</div>
        <div>Pane 1</div>
      </Allotment>
    </div>
  );
};

const NewWindow: FC<PropsWithChildren<{ newWindow: any }>> = ({
  children,
  newWindow,
}) => {
  useLayoutEffect(() => {
    document.head.querySelectorAll("link, style").forEach((htmlElement) => {
      newWindow.document.head.appendChild(htmlElement.cloneNode(true));
    });
  }, []);
  if (!newWindow) {
    return null;
  }
  return createPortal(children, newWindow?.document?.body);
};

export default App;


Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions