Window Replacement Cost Calculator

Window Replacement Calculators are a bit tricky – window replacement costs are highly variable depending on the area and the installer. 

We built this tool for a Michigan Screens, a window installer in Grand Rapids, MI so it is their data that’s currently inputted into this Window Replacement Cost Calculator. We have another window installation company in Chicago and the pricing wouldn’t be accurate for them.

The purpose of this post is two-fold. 

1. If you’re a consumer looking for window pricing you can use this to get a ball park.

2. If you’re a window installation company looking to build your own estimate tool you can take the code and edit it. For context, I’m not a developer – I possess the equivalent of a first grade level of coding ability. I can read some of it but mostly I’m using ChatGPT’s prompts to build out simple tools like this. I’ll walk you through the changes you need to make in the code and how to install it on your website and if you’re unable to do it, you can contact us and we can do it for you.

Build Your Own Window Cost Calculator Tool

Here are the steps and the code you’ll need to build your own tool. This is basically me synthesizing ChatGPT prompts and turning a four hour project into what should be a 1-2 hour project for someone of similar capabilities as me. 

If you’re not technical at all, this may take you a full day.

 

Step 1. Create a new folder on your desktop called window-calculator

Step 2. Create an index file with text editor.

Step 3. Copy and paste the code below.

Step 4. Make the changes to the Window Cost Calculator.

  1. Choose your own font
  2. Choose your own colors
  3. Add in the correct pricing
  4. Add in your own thumbnail images
  5. If you want customizations beyond that (eg: double vs triple pane windows or additional window styles).
Step 5. Open a Netlify account and launch a new project
Step 6. Embed the code on your website.

Window Calculator Code

				
					<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Window Price Calculator</title>
  <link href="https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&display=swap" rel="stylesheet">
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      theme: {
        extend: {
          fontFamily: {
            sans: ['Barlow', 'sans-serif'],
          }
        }
      }
    }
function toggleAccordion() {
  const body = document.getElementById('instruction-body');
  const icon = document.getElementById('accordion-icon');
  const isOpen = !body.classList.contains('hidden');

  if (isOpen) {
    body.classList.add('hidden');
    icon.classList.remove('rotate-180');
  } else {
    body.classList.remove('hidden');
    icon.classList.add('rotate-180');
  }
}
  </script>
</head>
<body data-rsssl=1 class="bg-white text-gray-800 font-sans">
    <div class="max-w-4xl mx-auto p-6">
      <h2 class="text-3xl font-bold mb-6 text-center">Window Price Calculator</h2>
  
      <div id="window-rows" class="space-y-6"></div>
  
      <div class="flex flex-col gap-4 mt-6">
        <button id="add-row-btn" onclick="addRow()" class="bg-[#1f273a] text-white px-6 py-2 rounded hover:brightness-110 transition">
          + Add Window
        </button>
  
        <button id="calculate-btn" onclick="calculateTotal()" class="bg-[#f9d908] text-black px-6 py-2 rounded hover:brightness-110 transition">
          Calculate Estimate
        </button>
      </div>


    <div id="result" class="mt-8 text-lg font-semibold bg-white p-4 rounded shadow-md"></div>
  </div>

  <script>
    const pricing = {
      Vinyl: {
        "Double Hung": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Sliding": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Awning": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Casement": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Bay": { Medium: [6500, 9000] },
        "Bow": { Medium: [7000, 9500] },
        "Egress": { Medium: [5500, 7500] },
        "Glass Block": { Medium: [1000, 5000] },
      },
      Composite: {
        "Double Hung": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Sliding": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Awning": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Casement": { Small: [1000, 5000], Medium: [1000, 5000], Large: [1000, 5000] },
        "Egress": { Medium: [6000, 8000] }
      }
    };

    const allStyles = [
      "Double Hung", "Sliding", "Awning", "Casement",
      "Bay", "Bow", "Egress", "Glass Block"
    ];

    const sizesByStyle = {
      "Double Hung": ["Small", "Medium", "Large"],
      "Sliding": ["Small", "Medium", "Large"],
      "Awning": ["Small", "Medium", "Large"],
      "Casement": ["Small", "Medium", "Large"],
      "Bay": ["Medium"],
      "Bow": ["Medium"],
      "Egress": ["Medium"],
      "Glass Block": ["Medium"]
    };

    const windowImages = {
      "Double Hung": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Sliding": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Awning": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Casement": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Bay": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Bow": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Egress": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png",
      "Glass Block": "https://www.saltwaterdigital.com/wp-content/uploads/2021/12/main-logo-darkblue.png"
    };

    function addRow() {
      const container = document.getElementById('window-rows');
      const row = document.createElement('div');
      row.className = 'flex flex-col sm:flex-row gap-4 items-start bg-white p-4 rounded shadow';

      const formControls = document.createElement('div');
      formControls.className = 'flex flex-col sm:flex-row gap-4 flex-wrap sm:items-center w-full sm:w-2/3';

      const styleSelect = document.createElement('select');
      styleSelect.className = 'px-3 py-2 border border-gray-300 rounded w-full sm:w-48';
      styleSelect.innerHTML = allStyles.map(style => `<option value="${style}">${style}</option>`).join('');
      formControls.appendChild(styleSelect);

      const sizeSelect = document.createElement('select');
      sizeSelect.className = 'px-3 py-2 border border-gray-300 rounded w-full sm:w-36';
      formControls.appendChild(sizeSelect);

      const qtyInput = document.createElement('input');
      qtyInput.type = 'number';
      qtyInput.min = 0;
      qtyInput.value = 1;
      qtyInput.className = 'px-3 py-2 border border-gray-300 rounded w-24';
      formControls.appendChild(qtyInput);

      const removeBtn = document.createElement('button');
      removeBtn.textContent = "Remove";
      removeBtn.className = 'text-red-600 hover:underline';
      removeBtn.onclick = () => row.remove();
      formControls.appendChild(removeBtn);

      const imageWrapper = document.createElement('div');
      imageWrapper.className = 'sm:w-1/3 w-full text-center';
      const img = document.createElement('img');
      img.src = windowImages[styleSelect.value];
      img.alt = styleSelect.value + ' Window';
      img.className = 'w-20 h-20 object-contain mx-auto';
      imageWrapper.appendChild(img);

      row.appendChild(formControls);
      row.appendChild(imageWrapper);
      container.appendChild(row);

      updateSizeOptions(styleSelect, sizeSelect);
      styleSelect.onchange = () => {
        updateSizeOptions(styleSelect, sizeSelect);
        img.src = windowImages[styleSelect.value];
        img.alt = styleSelect.value + ' Window';
      };
    }

    function updateSizeOptions(styleSelect, sizeSelect) {
      const style = styleSelect.value;
      const sizes = sizesByStyle[style];
      sizeSelect.innerHTML = sizes.length
        ? sizes.map(size => `<option value="${size}">${size}</option>`).join('')
        : `<option value="">N/A</option>`;
      sizeSelect.disabled = sizes.length === 0;
    }

    function calculateTotal() {
      const rows = document.querySelectorAll('#window-rows > div');
      let vinylMin = 0, vinylMax = 0;
      let compMin = 0, compMax = 0;
      let hasValidInput = false;
let disableComposite = false;

let selectionSummary = [];


      rows.forEach(row => {
  const [styleSelect, sizeSelect, qtyInput] = row.querySelectorAll('select, input');
  const style = styleSelect.value;
  const size = sizeSelect.value;
  const qty = parseInt(qtyInput.value) || 0;

  if (!style || !size || qty <= 0) return;

  hasValidInput = true;

selectionSummary.push(`${qty} ${size} ${style} Window${qty > 1 ? 's' : ''}`);


  if (["Bay", "Bow", "Glass Block"].includes(style)) {
    disableComposite = true;
  }

  const vinyl = pricing.Vinyl?.[style]?.[size];
  const comp = pricing.Composite?.[style]?.[size];

  if (vinyl) {
    vinylMin += vinyl[0] * qty;
    vinylMax += vinyl[1] * qty;
  }

  if (comp && !disableComposite) {
    compMin += comp[0] * qty;
    compMax += comp[1] * qty;
  }
});

      const totalMin = vinylMin + compMin;
      const totalMax = vinylMax + compMax;

const resultBox = document.getElementById('result');
if (!hasValidInput) {
  resultBox.innerHTML = "Please enter at least one valid window.";
  return;
}


let output = `
  <div class="mb-2 relative group inline-block">
    <span class="font-medium underline decoration-dotted cursor-help">
      Vinyl Window Total:
    </span>
    <div class="absolute hidden group-hover:block bg-gray-800 text-white text-xs rounded px-3 py-2 z-10 w-64 bottom-full mb-2 left-0 shadow-lg">
      Vinyl windows are typically more affordable due to lower material and manufacturing costs.
      <div class="absolute top-full left-4 w-3 h-3 bg-gray-800 rotate-45 transform origin-top-left"></div>
    </div>
    <span class="font-semibold ml-2" style="color: #1f273a;">
      $${vinylMin.toLocaleString()} – $${vinylMax.toLocaleString()}
    </span>
  </div>
`;

if (!disableComposite) {
  output += `
    <div class="mb-2">
      Composite Window Total:
      <span class="font-semibold" style="color: #1f273a;">
        $${compMin.toLocaleString()} – $${compMax.toLocaleString()}
      </span>
    </div>
  `;
} else {
  output += `
    <div class="mt-2 text-sm text-gray-600 italic">
      Composite estimate not available for selected window types (Bay, Bow, or Glass Block).
    </div>
  `;
}

if (selectionSummary.length > 0) {
  output += `
    <div class="mt-6">
      <p class="font-semibold mb-1">Your selections:</p>
      <ul class="list-disc pl-6 text-sm text-gray-700 mb-4">
        ${selectionSummary.map(item => `<li>${item}</li>`).join('')}
      </ul>
    <a 
  href="https://www.saltwaterdigital.com" 
  target="_blank"
  class="inline-block bg-[#f9d908] text-black text-lg font-bold tracking-wide px-8 py-3 rounded hover:brightness-110 transition"
>
  Contact Us For Quote On Your Project
</a>
    </div>
  `;
}

resultBox.innerHTML = output;

    }

    window.onload = () => addRow();
   window.onload = () => addRow();

  // Send height to parent window
  function sendHeightToParent() {
    const height = document.documentElement.scrollHeight;
    window.parent.postMessage({ type: 'resize', height }, '*');
  }

  // Watch for size changes and send updates
  const resizeObserver = new ResizeObserver(() => {
    sendHeightToParent();
  });
  resizeObserver.observe(document.body);
</script>
<footer class="text-center text-sm text-gray-500 mt-12 mb-4">
    Window Calculator by 
    <a href="https://www.saltwaterdigital.com" target="_blank" class="underline hover:text-gray-700">
      Salt Water Digital
    </a>
  </footer>
</body>
</html>

				
			

Embed Code

				
					<iframe 
  id="window-calculator"
  src="https://your-URL-from.netlify.app/" 
  width="100%" 
  style="border: none;" 
  title="Window Price Calculator">
</iframe>

<script>
  window.addEventListener("message", function (event) {
    if (event.data?.type === "resize") {
      const iframe = document.getElementById("window-calculator");
      if (iframe) {
        iframe.style.height = event.data.height + "px";
      }
    }
  });
</script>
				
			

Sign up for our newsletter

Share:

Table of Contents

Subscribe

Subscribe to our quarterly local SEO & Google Ads newsletter. No-nonsense articles on search and paid advertising for small businesses.

Related Posts

Roisin’s Volunteering for Earth Day

For Earth Day 2025, the Trout Lake Community Centre in Vancouver held a free family-friendly celebration day that I volunteered at, representing the BC Wildlife Federation. The

Window Replacement Cost Calculator

Window Replacement Calculators are a bit tricky – window replacement costs are highly variable depending on the area and the installer.  We built this tool

Skip to content