DEV Community

Cover image for 7 Vanilla JavaScript Tricks I Learned Building 70+ Browser Tools (No Framework)
The AI producer
The AI producer

Posted on

7 Vanilla JavaScript Tricks I Learned Building 70+ Browser Tools (No Framework)

When I set out to build a hub of 70+ free browser utilities — from a JSON formatter to a QR code generator to a regex tester — I made one rule: no build step, no framework, no backend. Everything runs client-side, works offline, and respects user privacy by design.

What surprised me was how far modern vanilla JavaScript alone could carry a real product. Here are seven patterns I reached for again and again — each one replaces what used to require a library.

1. The Clipboard API (with a graceful fallback)

Every "copy to clipboard" button in the tools uses this. It's async, secure, and finally universal:

async function copyText(text) {
  try {
    await navigator.clipboard.writeText(text);
    return true;
  } catch {
    // Fallback for insecure contexts (http://) and older browsers
    const ta = document.createElement('textarea');
    ta.value = text;
    ta.style.position = 'fixed';
    ta.style.opacity = '0';
    document.body.appendChild(ta);
    ta.select();
    const ok = document.execCommand('copy');
    document.body.removeChild(ta);
    return ok;
  }
}
Enter fullscreen mode Exit fullscreen mode

The navigator.clipboard API only works on secure origins (HTTPS or localhost). The fallback keeps tools usable everywhere — important when users self-host.

2. Reading Files Without a Server

A Base64 encoder, an image converter, a hash calculator — all of them read a local file without uploading anything. The secret is FileReader (or its modern sibling Blob.text()):

function onFile(file, cb) {
  const reader = new FileReader();
  reader.onload = () => cb(reader.result);
  reader.readAsDataURL(file); // or readAsText / readAsArrayBuffer
}
Enter fullscreen mode Exit fullscreen mode

Because the file never leaves the browser, a privacy-conscious user can paste sensitive data into a JSON validator and trust that nothing is transmitted. That's a genuine product advantage you can advertise.

3. Native Crypto for Hashing

Need a SHA-256 checksum? You don't need a dependency — crypto.subtle ships in every modern browser:

async function sha256(text) {
  const data = new TextEncoder().encode(text);
  const hash = await crypto.subtle.digest('SHA-256', data);
  return [...new Uint8Array(hash)]
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}
Enter fullscreen mode Exit fullscreen mode

The same API supports HMAC, AES-GCM encryption, and key derivation (PBKDF2). A surprising amount of "security tooling" is just this one interface.

4. Generating Downloads From Memory

A "download as PNG" button on the QR code generator, "export JSON" on the formatter — all done by constructing a Blob and triggering a download, no server round-trip:

function download(filename, content, type = 'text/plain') {
  const blob = new Blob([content], { type });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url); // free the memory
}
Enter fullscreen mode Exit fullscreen mode

For canvas-based tools (the color palette, QR generator), swap content for canvas.toBlob(...) — same pattern, zero extra code.

5. Parsing the URL Without Regex

A URL shortener previewer, a query-param editor, and an "extract links" tool all lean on the built-in URL and URLSearchParams objects. Stop writing fragile regex:

const u = new URL('https://example.com/tools?q=js&page=2#section');
console.log(u.hostname);            // example.com
console.log(u.searchParams.get('q')); // js
u.searchParams.set('page', '3');
console.log(u.toString());          // updated URL
Enter fullscreen mode Exit fullscreen mode

This single API replaced dozens of buggy split('?') hacks across the tools.

6. Debounce — The 12-Line Performance Win

A live regex tester, a markdown preview, a color converter — anything that reacts to typing must be debounced, or you'll recompute on every keystroke. No need for Lodash:

function debounce(fn, ms = 200) {
  let t;
  return (...args) => {
    clearTimeout(t);
    t = setTimeout(() => fn(...args), ms);
  };
}

input.addEventListener('input', debounce(() => {
  output.textContent = renderMarkdown(input.value);
}, 150));
Enter fullscreen mode Exit fullscreen mode

This one pattern turned laggy, janky tools into instant-feeling ones.

7. Modern UUIDs and Random Values

The UUID generator is genuinely one line:

const uuid = crypto.randomUUID(); // "3f0e1b2a-..."
Enter fullscreen mode Exit fullscreen mode

For anything security-sensitive (tokens, passwords), reach for crypto.getRandomValues instead of Math.random() — the latter is not cryptographically secure and should never seed a password generator:

function randomBytes(len) {
  const arr = new Uint8Array(len);
  crypto.getRandomValues(arr);
  return arr;
}
Enter fullscreen mode Exit fullscreen mode

The Bigger Lesson

The recurring theme: the browser is a remarkably complete runtime in 2026. Clipboard access, file reading, cryptography, URL parsing, memory-only downloads — all of it ships natively. The "I need a library for that" instinct is often outdated, and dropping it makes your tools faster to build, faster to load, and more private by default.

If you want to poke around working examples of every pattern above, I keep them all in a single hub:

Free Tools Hub — 70+ browser utilities, no sign-up

Each one is a single static page, so you can view-source any of them to see the exact implementation. Happy hacking.


What vanilla JS patterns do you find yourself reaching for? I'm always looking for new ones to add to the toolbox.

Top comments (0)