{"slug": "i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero", "title": "I Built a Unit Converter in Pure Vanilla JS — 7 Categories, 70+ Units, 165 Tests, Zero Dependencies", "summary": "A developer built a unit converter in pure vanilla JavaScript that supports seven categories and over 70 units, with 165 tests and zero dependencies. The tool runs entirely in the browser with no tracking or server round-trips, handling both linear and non-linear conversions like temperature. It is part of the devnestio collection of free, zero-dependency developer tools.", "body_md": "Unit converters are everywhere online, but they all seem to either require an account, run ads that cover half the screen, or send your input to a server for no reason. I built one that runs entirely in your browser, with no dependencies, no tracking, and no round-trips.\n\n👉 [https://unit-converter-dev.pages.dev](https://unit-converter-dev.pages.dev)\n\nSeven conversion categories, 70+ units, real-time bidirectional conversion:\n\n| Category | Example units |\n|---|---|\nLength |\nmm, cm, m, km, in, ft, yd, mi, nmi, light-year |\nWeight |\nmg, g, kg, t, oz, lb, st, short ton |\nTemperature |\n°C, °F, K, °R |\nVolume |\nml, l, m³, fl oz, cup, pint, quart, gallon, tbsp, tsp |\nArea |\nmm², cm², m², km², ha, acre, ft², in², mi², yd² |\nSpeed |\nm/s, km/h, mph, ft/s, knot, Mach |\nData |\nbit, byte, KB/KiB, MB/MiB, GB/GiB, TB — both SI and binary |\n\nFeatures:\n\nMost unit conversions are linear: multiply by a factor to get to the base unit, divide by another factor to get to the target. The approach:\n\n``` js\nfunction convert(catKey, fromUnit, toUnit, value) {\n  const base = toBase(catKey, fromUnit, value);     // → base unit\n  return fromBase(catKey, toUnit, base);            // base unit → target\n}\n\nfunction toBase(catKey, unit, value) {\n  const u = CATEGORIES[catKey].units[unit];\n  if (u.toBase) return u.toBase(value);             // non-linear (temperature)\n  return value * u.factor;\n}\n```\n\nTemperature is the classic non-linear case. You can't just multiply to convert between Celsius, Fahrenheit, and Kelvin — you need offset arithmetic:\n\n``` js\ntemperature: {\n  units: {\n    C: {\n      toBase:   v => v + 273.15,               // °C → K\n      fromBase: v => v - 273.15,               // K → °C\n    },\n    F: {\n      toBase:   v => (v - 32) * 5/9 + 273.15, // °F → K\n      fromBase: v => (v - 273.15) * 9/5 + 32, // K → °F\n    },\n    K: { toBase: v => v, fromBase: v => v },\n    R: { toBase: v => v * 5/9, fromBase: v => v * 9/5 },\n  }\n}\n```\n\nThe data category includes both SI prefixes (1 KB = 1000 bytes) and binary prefixes (1 KiB = 1024 bytes). Both are represented with the same factor-based approach, just stored as separate units:\n\n```\ndata: {\n  units: {\n    kB:  { factor: 8e3     },  // Kilobyte  = 8000 bits\n    kiB: { factor: 8192    },  // Kibibyte  = 8192 bits (= 8 × 1024)\n    mB:  { factor: 8e6     },  // Megabyte  = 8,000,000 bits\n    miB: { factor: 8388608 },  // Mebibyte  = 8,388,608 bits (= 8 × 1024²)\n    // ...\n  }\n}\n```\n\nThe tricky part is displaying results cleanly. `1.6093440000000001`\n\nis ugly; `1.609344`\n\nis what you want. `toPrecision(10)`\n\nthen `parseFloat`\n\nremoves trailing zeros while keeping enough precision:\n\n```\nfunction formatNum(n) {\n  if (!isFinite(n)) return '';\n  if (n === 0) return '0';\n  const abs = Math.abs(n);\n  if (abs >= 1e-3 && abs < 1e13) {\n    return parseFloat(n.toPrecision(10)).toString();\n  }\n  return n.toExponential(6);  // very large or very small → scientific notation\n}\n```\n\n165 tests, all passing, using only Node.js `assert`\n\n:\n\n```\n§1  Length conversions         (17 tests)\n§2  Weight conversions         (12 tests)\n§3  Temperature conversions    (13 tests)\n§4  Volume conversions         (11 tests)\n§5  Area conversions           (10 tests)\n§6  Speed conversions          ( 9 tests)\n§7  Data conversions           (12 tests)\n§8  formatNum                  (15 tests)\n§9  convert edge cases         ( 8 tests)\n§10 Roundtrip conversions      (13 tests)\n§11 Category structure         (12 tests)\n§12 Known reference values     (13 tests)\n§13 Additional coverage        (20 tests)\n```\n\nHighlights from the test suite:\n\n`-40°C = -40°F`\n\n(the only point where Celsius and Fahrenheit are equal)`0 K = -459.67°F`\n\n(absolute zero)`1 mi = 5280 ft = 1760 yd = 1.609344 km`\n\n`1 GiB = 1024 MiB = 8589934592 bits`\n\n👉 [https://unit-converter-dev.pages.dev](https://unit-converter-dev.pages.dev)\n\nPart of [devnestio](https://devnestio.pages.dev) — a collection of free, zero-dependency developer tools that run entirely in your browser.", "url": "https://wpnews.pro/news/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero", "canonical_source": "https://dev.to/dev_nestio_229945f10652e4/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero-dependencies-3n2o", "published_at": "2026-06-28 00:22:00+00:00", "updated_at": "2026-06-28 00:33:41.373647+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["devnestio", "Node.js"], "alternates": {"html": "https://wpnews.pro/news/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero", "markdown": "https://wpnews.pro/news/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero.md", "text": "https://wpnews.pro/news/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero.txt", "jsonld": "https://wpnews.pro/news/i-built-a-unit-converter-in-pure-vanilla-js-7-categories-70-units-165-tests-zero.jsonld"}}