[object Object]

← back to Estimate Instant

estimate-instant: add embeddable widget (embed.js iframe snippet + auto-height postMessage) — matches brief's 200+-site embed thesis

6ec2a7c0b53ee4222c31bd8e5058ac87ced0b86a · 2026-07-15 16:52:04 -0700 · Steve

Files touched

Diff

commit 6ec2a7c0b53ee4222c31bd8e5058ac87ced0b86a
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 15 16:52:04 2026 -0700

    estimate-instant: add embeddable widget (embed.js iframe snippet + auto-height postMessage) — matches brief's 200+-site embed thesis
---
 public/embed.js   | 32 ++++++++++++++++++++++++++++++++
 public/index.html |  4 ++++
 2 files changed, 36 insertions(+)

diff --git a/public/embed.js b/public/embed.js
new file mode 100644
index 0000000..fe81dc2
--- /dev/null
+++ b/public/embed.js
@@ -0,0 +1,32 @@
+// estimate-instant — drop-in embed for any DW sister site.
+// Usage on the host page:
+//   <div id="dw-estimate"></div>
+//   <script src="https://estimate.designerwallcoverings.com/embed.js"
+//           data-target="#dw-estimate" data-height="720"></script>
+// Renders the calculator in a sandboxed iframe so host-page CSS can't leak in
+// and captured emails post back to THIS origin (single source of truth for the
+// roll-math + the lead store). No host-page dependencies.
+(function () {
+  var s = document.currentScript;
+  if (!s) return;
+  // Origin the script itself was loaded from — the widget always talks home.
+  var origin = new URL(s.src, location.href).origin;
+  var sel = s.getAttribute('data-target') || '#dw-estimate';
+  var height = parseInt(s.getAttribute('data-height') || '720', 10);
+  var mount = document.querySelector(sel);
+  if (!mount) { console.warn('[estimate-instant] embed target not found:', sel); return; }
+
+  var f = document.createElement('iframe');
+  f.src = origin + '/?embed=1';
+  f.title = 'Wallpaper roll estimate';
+  f.loading = 'lazy';
+  f.setAttribute('scrolling', 'no');
+  f.style.cssText = 'width:100%;border:0;display:block;max-width:680px;margin:0 auto;height:' + height + 'px';
+  // Let the widget grow to fit its content once loaded (see index.html postMessage).
+  window.addEventListener('message', function (e) {
+    if (e.origin === origin && e.data && e.data.dwEstimateHeight) {
+      f.style.height = e.data.dwEstimateHeight + 'px';
+    }
+  });
+  mount.appendChild(f);
+})();
diff --git a/public/index.html b/public/index.html
index effe93e..cbc0961 100644
--- a/public/index.html
+++ b/public/index.html
@@ -99,7 +99,11 @@ async function calc(){
     ['Price per roll','$'+r.pricePerRoll],['Est. waste',r.wastePct+'%']
   ].map(([k,v])=>`<div>${k}: <b>${v}</b></div>`).join('');
   $('result').classList.add('show'); $('done').style.display='none';
+  postHeight();
 }
+// When embedded via embed.js, report our content height so the host iframe can grow.
+function postHeight(){ if(parent!==window){ try{ parent.postMessage({dwEstimateHeight:document.body.scrollHeight+24},'*'); }catch(e){} } }
+window.addEventListener('load',postHeight);
 $('go').addEventListener('click',calc);
 $('send').addEventListener('click',async()=>{
   const email=$('email').value.trim();

← 324b6db estimate-instant: fix half-drop math (consume match), honest  ·  back to Estimate Instant  ·  estimate-instant: add embed-demo.html, fix /admin route + au f93b004 →