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)