Dev.to WebDev 🛠 Dev 👁 0 📖 3 min read

Three interactive calculators, zero dependencies: a static-site pattern

Static sites have one obvious limitation: no server. So when I wanted to add calculators to a content site, the answer was not a backend — it was about 40 lines of vanilla JS per tool. Here are three patterns I ended up

Static sites have one obvious limitation: no server. So when I wanted to add calculators to a content site, the answer was not a backend — it was about 40 lines of vanilla JS per tool.

Here are three patterns I ended up reusing, with the real tools linked so you can see them working.

Pattern 1: unit conversion with a formula

The first tool is a raised bed soil calculator. The whole thing is one formula — volume = length × width × depth — plus unit conversion and rounding.

var U = { cm: 0.01, m: 1, ft: 0.3048, in: 0.0254 };

function run() {
  var f = U[document.getElementById("unit").value];
  var L = parseFloat(document.getElementById("len").value) * f;
  var W = parseFloat(document.getElementById("wid").value) * f;
  var D = parseFloat(document.getElementById("dep").value) * f;
  if (!(L > 0 && W > 0 && D > 0)) return;
  var m3 = L * W * D;
  // ...render
}

The part that matters is the guard clause. Users will type 0, -, or nothing, and a calculator that renders NaN looks broken.

Live version: Raised Bed Soil Calculator

Pattern 2: rule-based sizing

The second tool takes a count and applies rules. A chicken coop needs 2–3 sq ft per bird inside and 8–10 sq ft in the run, plus one nest box per five hens.

The interesting design decision is exposing the rules as a dropdown rather than hardcoding one standard:

<select id="space">
  <option value="2,8">Minimum (2 + 8 sq ft)</option>
  <option value="3,10" selected>Comfortable (3 + 10 sq ft)</option>
  <option value="4,12">Generous (4 + 12 sq ft)</option>
</select>
var parts = document.getElementById("space").value.split(",");
var inside = parseFloat(parts[0]);
var run = parseFloat(parts[1]);
var coopSqFt = n * inside;

Encoding the rules in the markup rather than in JS means you can add a preset without touching the logic.

Live version: Chicken Coop Size Calculator

Pattern 3: client-side filtering as a "tool"

The third one is not a calculator at all — it is a search filter over a static table. 24 rows of food storage times, filtered as you type.

var rows = [].slice.call(document.querySelectorAll("tr[data-k]"));
function run() {
  var v = q.value.trim().toLowerCase();
  rows.forEach(function (r) {
    r.style.display = r.getAttribute("data-k").indexOf(v) >= 0 ? "" : "none";
  });
}
q.addEventListener("input", run);

The trick is the data-k attribute holding a pre-lowercased search key. It means you can search for text that is not visible in the row — synonyms, alternate spellings, unit names.

Live version: Food Storage Time Lookup

Why bother on a static site

Three reasons that turned out to matter more than I expected:

  1. No build step. The JS is inline in the page. Nothing to compile, nothing to version.
  2. Works with JS disabled. The content is a real HTML table or a real list of numbers. The tool is an enhancement, not a requirement.
  3. Tools earn links. People link to "this calculator" far more readily than to "this article". For a new site with no authority, that is the whole game.

The bit that is easy to get wrong

Mobile. All three tools use a flex row with flex-wrap: wrap and a full-width input below 620px. Without that, the labels and inputs fight for space and the tool becomes unusable on a phone — which is where most traffic actually is.

@media (max-width: 620px) {
  .calc-row label { flex: 0 0 100%; }
  .calc-row input { width: 100%; }
}

If you have built tools like this on a static host, I would be curious what patterns you reused. The three above cover most of what I needed, but I suspect there is a fourth one I have not hit yet.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.