A multi-category unit converter with instant live conversion for length, weight, temperature, and speed — with a swap button to reverse direction.
Store each category as an object mapping unit names to their conversion factor relative to a base unit.
// All values relative to the base unit (first in each category)
const CATEGORIES = {
Length: {
base: 'meters',
units: {
meters: 1, kilometers: 0.001, centimeters: 100, millimeters: 1000,
miles: 0.000621371, yards: 1.09361, feet: 3.28084, inches: 39.3701,
},
},
Weight: {
base: 'kilograms',
units: {
kilograms: 1, grams: 1000, milligrams: 1e6,
pounds: 2.20462, ounces: 35.274, tonnes: 0.001,
},
},
Temperature: { special: true }, // handled separately
Speed: {
base: 'km/h',
units: { 'km/h': 1, 'm/s': 0.277778, mph: 0.621371, knots: 0.539957 },
},
};
function convert(value, fromUnit, toUnit, category) {
if (category === 'Temperature') return convertTemp(value, fromUnit, toUnit);
const cat = CATEGORIES[category];
const inBase = value / cat.units[fromUnit];
return inBase * cat.units[toUnit];
}
function convertTemp(v, from, to) {
let celsius;
if (from === 'Celsius') celsius = v;
else if (from === 'Fahrenheit') celsius = (v - 32) * 5/9;
else celsius = v - 273.15;
if (to === 'Celsius') return celsius;
else if (to === 'Fahrenheit') return celsius * 9/5 + 32;
else return celsius + 273.15;
}
console.log(convert(100, 'kilometers', 'miles', 'Length').toFixed(3)); // 62.137
console.log(convert(100, 'Celsius', 'Fahrenheit', 'Temperature')); // 212
Dynamic dropdowns that repopulate when you switch category.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Unit Converter</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',sans-serif; background:#0f172a; color:#f8fafc; min-height:100vh; display:flex; align-items:center; justify-content:center; padding:20px; }
.card { background:#1e293b; border-radius:20px; padding:36px; max-width:460px; width:100%; }
h1 { font-size:1.4rem; text-align:center; margin-bottom:24px; }
.tabs { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:28px; }
.tab { flex:1; min-width:80px; padding:8px 4px; border:none; background:#334155; color:#94a3b8; border-radius:8px; cursor:pointer; font-size:0.8rem; font-weight:600; transition:all 0.2s; }
.tab.active { background:#3b82f6; color:#fff; }
.row { display:flex; align-items:center; gap:12px; margin-bottom:16px; }
.col { flex:1; display:flex; flex-direction:column; gap:6px; }
label { font-size:0.75rem; color:#94a3b8; font-weight:600; text-transform:uppercase; letter-spacing:0.05em; }
input, select { width:100%; padding:11px 14px; background:#0f172a; border:1px solid #334155; color:#f8fafc; border-radius:10px; font-size:0.95rem; }
input:focus, select:focus { outline:none; border-color:#3b82f6; }
.swap-btn { background:#334155; border:none; color:#94a3b8; font-size:1.2rem; padding:10px; border-radius:10px; cursor:pointer; flex-shrink:0; transition:all 0.2s; margin-top:16px; }
.swap-btn:hover { background:#3b82f6; color:#fff; }
</style>
</head>
<body>
<?php require_once __DIR__ . '/../promo_banner.php'; ?>
<div class="card">
<h1>📐 Unit Converter</h1>
<div class="tabs" id="tabs"></div>
<div class="row">
<div class="col"><label>From</label><input type="number" id="fromVal" value="1" oninput="doConvert(false)"><select id="fromUnit" onchange="doConvert(false)"></select></div>
<button class="swap-btn" onclick="swap()">⇄</button>
<div class="col"><label>To</label><input type="number" id="toVal" oninput="doConvert(true)"><select id="toUnit" onchange="doConvert(false)"></select></div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
Build tabs, populate selects, and run the conversion on every keypress.
// app.js (paste conversion logic from Step 1 first)
const TEMP_UNITS = ['Celsius', 'Fahrenheit', 'Kelvin'];
let currentCategory = 'Length';
function buildTabs() {
const tabs = document.getElementById('tabs');
Object.keys(CATEGORIES).forEach(cat => {
const btn = document.createElement('button');
btn.className = 'tab' + (cat === currentCategory ? ' active' : '');
btn.textContent = cat;
btn.onclick = () => { currentCategory = cat; buildTabs(); buildSelects(); doConvert(false); };
tabs.appendChild(btn);
});
}
function buildSelects() {
const units = currentCategory === 'Temperature' ? TEMP_UNITS : Object.keys(CATEGORIES[currentCategory].units);
['fromUnit','toUnit'].forEach((id, i) => {
const sel = document.getElementById(id);
sel.innerHTML = units.map((u,j) => `<option value="${u}" ${j === i ? 'selected' : ''}>${u}</option>`).join('');
});
}
function doConvert(reversed) {
const fromVal = parseFloat(document.getElementById('fromVal').value);
const fromUnit = document.getElementById('fromUnit').value;
const toUnit = document.getElementById('toUnit').value;
if (isNaN(fromVal)) return;
const result = convert(fromVal, fromUnit, toUnit, currentCategory);
document.getElementById(reversed ? 'fromVal' : 'toVal').value = parseFloat(result.toFixed(8));
}
function swap() {
const fU = document.getElementById('fromUnit').value;
const tU = document.getElementById('toUnit').value;
document.getElementById('fromUnit').value = tU;
document.getElementById('toUnit').value = fU;
doConvert(false);
}
buildTabs(); buildSelects(); doConvert(false);
You built a four-category converter that handles both linear units and temperature. Add more categories by extending the CATEGORIES object — each new category automatically gets a tab and populated dropdowns.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.