Opening a popup window in React isn't hard—but managing communication between your app and that popup can get tricky. In this article, you'll learn how to:
- Open a new browser window (popup)
- Send data from the parent React app to the popup
- Detect when the popup is closed
We’ll be using React Function Components with TypeScript to make this solution strongly typed and future-proof.
🧠 What You’ll Learn
- How to open a popup window with specific dimensions
- How to communicate with that popup window using
postMessage
- How to watch for popup closure using
setInterval
- A clean, reusable TypeScript implementation
📦 Let’s Build It!
1. Create the Popup Component
This component will live inside the popup window and receive data from the parent window using message
events.
// PopupPage.tsx
import { useEffect, useState } from 'react';
const PopupPage = () => {
const [message, setMessage] = useState<any>(null);
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
// Optionally: restrict to same-origin in production
if (event.origin !== window.location.origin) return;
console.log('Received message:', event.data);
setMessage(event.data);
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
return (
<div style={{ padding: 20 }}>
<h2>Popup Window</h2>
<p>
<strong>Message from parent:</strong>
</p>
<pre style={{ background: '#eee', padding: '10px' }}>
{message ? JSON.stringify(message, null, 2) : 'No message received'}
</pre>
</div>
);
};
export default PopupPage;
2. Create the Main App with Popup Logic
This component handles the logic to open the popup, send a message, and watch for closure.
// App.tsx
import React, { useRef, useState } from 'react';
const App: React.FC = () => {
const popupRef = useRef<Window | null>(null);
const timerRef = useRef<NodeJS.Timer | null>(null);
const [popupOpen, setPopupOpen] = useState(false);
const openPopup = () => {
if (popupRef.current && !popupRef.current.closed) {
popupRef.current.focus();
return;
}
const width = 400;
const height = 300;
const left = window.screenX + (window.outerWidth - width) / 2;
const top = window.screenY + (window.outerHeight - height) / 2;
popupRef.current = window.open(
'/popup',
'MyPopup',
`width=${width},height=${height},left=${left},top=${top}`
);
if (popupRef.current) {
setPopupOpen(true);
startWatcher();
}
};
const sendMessage = () => {
popupRef.current?.postMessage('Hello from parent!', window.origin);
};
const startWatcher = () => {
timerRef.current = setInterval(() => {
if (!popupRef.current || popupRef.current.closed) {
clearInterval(timerRef.current!);
timerRef.current = null;
popupRef.current = null;
setPopupOpen(false);
alert('Popup was closed');
}
}, 500);
};
return (
<div style={{ padding: 20 }}>
<h1>React Popup Communication (TS)</h1>
<button onClick={openPopup}>Open Popup</button>
<button onClick={sendMessage} disabled={!popupOpen}>
Send Message
</button>
</div>
);
};
export default App;
🛣️ Setting Up the Route for the Popup
If you're using React Router, you can route the popup like this:
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import App from './App';
import PopupPage from './PopupPage';
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/popup" element={<PopupPage />} />
</Routes>
</BrowserRouter>
);
☕ Enjoyed this post?
If you'd like to support my work, you can buy me a coffee — it really helps and means a lot!
Top comments (0)