React component and hook for handling window and document object in iframe or SSR environment
npx @tessl/cli install tessl/npm-chakra-ui--react-env@3.1.0Chakra UI React Environment provides React component and hook for handling window and document object in iframe or SSR environment. It enables React applications to safely access window and document objects in server-side rendering (SSR) and iframe contexts where standard globals may not be available or may refer to the wrong context.
npm install @chakra-ui/react-envimport { EnvironmentProvider, useEnvironment } from "@chakra-ui/react-env";
import type { EnvironmentProviderProps } from "@chakra-ui/react-env";For CommonJS:
const { EnvironmentProvider, useEnvironment } = require("@chakra-ui/react-env");import { EnvironmentProvider, useEnvironment } from "@chakra-ui/react-env";
// Wrap your app in EnvironmentProvider
function App({ children }) {
return (
<EnvironmentProvider>
{children}
</EnvironmentProvider>
);
}
// Use the hook to access window/document safely
function WindowSize() {
const { getWindow, getDocument } = useEnvironment();
const window = getWindow();
const document = getDocument();
return (
<div>
Window size: {window.innerWidth}x{window.innerHeight}
</div>
);
}The package is built around React Context pattern:
The main component that establishes environment context for child components.
function EnvironmentProvider(props: EnvironmentProviderProps): JSX.Element;
interface EnvironmentProviderProps {
/** Child components to render within the environment context */
children: React.ReactNode;
/** Whether to disable the hidden span element used for context detection */
disabled?: boolean;
/** Custom environment object to use instead of auto-detection */
environment?: Environment;
}
interface Environment {
/** Get the current window object for this environment */
getWindow: () => Window;
/** Get the current document object for this environment */
getDocument: () => Document;
}Usage Examples:
// Basic usage - auto-detects correct window/document
<EnvironmentProvider>
<MyApp />
</EnvironmentProvider>
// Iframe usage - detects iframe's window/document
<Frame>
<EnvironmentProvider>
<IframeContent />
</EnvironmentProvider>
</Frame>
// Custom environment
const customEnv = {
getWindow: () => someSpecificWindow,
getDocument: () => someSpecificDocument,
};
<EnvironmentProvider environment={customEnv}>
<SpecializedComponent />
</EnvironmentProvider>
// Disabled mode (no hidden span element)
<EnvironmentProvider disabled>
<StaticContent />
</EnvironmentProvider>React hook for accessing the current environment context within components.
function useEnvironment(options?: { defer?: boolean }): Environment;
interface Environment {
/** Get the current window object for this environment */
getWindow: () => Window;
/** Get the current document object for this environment */
getDocument: () => Document;
}Parameters:
options.defer (optional): If true, forces a re-render after component mount. Useful for SSR scenarios where initial render needs to differ from hydrated render.Usage Examples:
// Basic usage
const { getWindow, getDocument } = useEnvironment();
const window = getWindow();
const document = getDocument();
// SSR-safe usage with defer
const { getWindow } = useEnvironment({ defer: true });
const [windowSize, setWindowSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const window = getWindow();
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
}, [getWindow]);
// Media query usage
const { getWindow } = useEnvironment();
useEffect(() => {
const window = getWindow();
const mediaQuery = window.matchMedia('(min-width: 768px)');
const handler = (e: MediaQueryListEvent) => {
setIsMobile(!e.matches);
};
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}, [getWindow]);Handle window/document access during SSR where these globals are undefined:
function ResponsiveComponent() {
const { getWindow } = useEnvironment({ defer: true });
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
// Safe to access window after hydration
const window = getWindow();
setIsMobile(window.innerWidth < 768);
}, [getWindow]);
return <div>Mobile: {isMobile}</div>;
}Ensure components inside iframes use the iframe's window/document:
// Parent component
function ParentWithIframe() {
return (
<div>
<h1>Parent Window</h1>
<Frame>
<EnvironmentProvider>
<IframeContent />
</EnvironmentProvider>
</Frame>
</div>
);
}
// Component inside iframe
function IframeContent() {
const { getWindow, getDocument } = useEnvironment();
// These will refer to the iframe's window/document
const window = getWindow();
const document = getDocument();
return <div>Iframe size: {window.innerWidth}x{window.innerHeight}</div>;
}Provide specific window/document objects for testing or special scenarios:
// Test environment
const mockEnvironment = {
getWindow: () => ({
innerWidth: 1024,
innerHeight: 768,
matchMedia: () => ({ matches: true })
} as Window),
getDocument: () => document
};
// In tests
<EnvironmentProvider environment={mockEnvironment}>
<ComponentUnderTest />
</EnvironmentProvider>