diff --git a/apps/web/src/components/EmailEditor/EmailEditor.tsx b/apps/web/src/components/EmailEditor/EmailEditor.tsx index d7f80c9..4a1ad9d 100644 --- a/apps/web/src/components/EmailEditor/EmailEditor.tsx +++ b/apps/web/src/components/EmailEditor/EmailEditor.tsx @@ -306,21 +306,31 @@ export function EmailEditor({value, onChange, placeholder, subject, from, replyT iframeDoc.write(fullHtml); iframeDoc.close(); - // Auto-adjust iframe height to content + // Auto-adjust iframe height to content. Reset to a small value first so + // body content that uses % / vh heights doesn't lock the iframe to its + // previous size (which would otherwise cause the iframe to grow by the + // padding offset on every preview-device switch). const adjustHeight = () => { - if (iframe.contentWindow) { - const height = iframe.contentWindow.document.body.scrollHeight; - iframe.style.height = `${Math.max(400, height + 40)}px`; - } + if (!iframe.contentWindow) return; + iframe.style.height = '0px'; + const doc = iframe.contentWindow.document; + const height = Math.max( + doc.body?.scrollHeight ?? 0, + doc.documentElement?.scrollHeight ?? 0, + ); + iframe.style.height = `${Math.max(400, height + 40)}px`; }; - // Adjust height after content loads - if (iframe.contentWindow) { - iframe.contentWindow.addEventListener('load', adjustHeight); - // Also adjust immediately for already-loaded content - setTimeout(adjustHeight, 100); - setTimeout(adjustHeight, 300); // Fallback for slow-loading images - } + const timeouts = [ + window.setTimeout(adjustHeight, 100), + window.setTimeout(adjustHeight, 300), + ]; + iframe.contentWindow?.addEventListener('load', adjustHeight); + + return () => { + timeouts.forEach(window.clearTimeout); + iframe.contentWindow?.removeEventListener('load', adjustHeight); + }; } } // eslint-disable-next-line react-hooks/exhaustive-deps