DEV Community

Cover image for Stop Installing Libraries: 13 Native APIs That Went Baseline in 2026
Gos
Gos

Posted on

Stop Installing Libraries: 13 Native APIs That Went Baseline in 2026

TL;DR: The browser caught up while you weren't looking. As of 2026, all 13 of these APIs are Baseline — supported across every major browser — so you can finally delete moment, lodash, axios, uuid, numeral, clipboard.js and more. Running tally at the bottom: ~115 KB gzipped, gone. Copy-paste code for each.

You keep reaching for a package out of muscle memory. But "Baseline" now means these APIs work everywhere that matters — so the dependency you're about to install is dead weight. Here's what you can delete today, with the bundle savings for each.

1. structuredClone() → delete lodash.clonedeep (−5 KB)

JSON.parse(JSON.stringify(x)) silently mangles Date, Map, Set, and undefined. The platform has a real deep clone:

const state = {
  user: { name: "Ada" },
  visited: new Set([1, 2, 3]),
  updatedAt: new Date(),
};

const copy = structuredClone(state);
copy.user.name = "Grace";

state.user.name;              // "Ada" — untouched
copy.visited instanceof Set;  // true, real Set preserved
Enter fullscreen mode Exit fullscreen mode

Handles Maps, Sets, Dates, typed arrays, and circular refs. (Caveats in Gotchas.)

2. crypto.randomUUID() → delete uuid (−1 KB)

const id = crypto.randomUUID();
// "1e7c8b2a-5f3d-4a1b-9c2e-8d6f0a3b1c4d"
Enter fullscreen mode Exit fullscreen mode

Spec-compliant v4, cryptographically random. Only needs a secure context (HTTPS or localhost) — which you already have.

3. Intl.RelativeTimeFormat + a 6-line helper → delete moment (−72 KB)

This is the big one. Moment does compute the delta and pick the unit for you — the native API doesn't, so pair it with a tiny helper (this is the part everyone trips on):

const DIVISIONS = [
  { amount: 60, unit: "second" },
  { amount: 60, unit: "minute" },
  { amount: 24, unit: "hour" },
  { amount: 7, unit: "day" },
  { amount: 4.34524, unit: "week" },
  { amount: 12, unit: "month" },
  { amount: Infinity, unit: "year" },
];
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });

function timeAgo(date) {
  let duration = (date - Date.now()) / 1000; // seconds; negative = past
  for (const { amount, unit } of DIVISIONS) {
    if (Math.abs(duration) < amount) return rtf.format(Math.round(duration), unit);
    duration /= amount;
  }
}

timeAgo(new Date(Date.now() - 3 * 60_000)); // "3 minutes ago"
Enter fullscreen mode Exit fullscreen mode

numeric: "auto" gives you "yesterday" for free, localized in every language the browser ships — no locale bundles.

4. Intl.NumberFormat → delete numeral.js (−3.6 KB)

Currency, units, and compact notation, all localized:

new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(1234.5);
// "$1,234.50"
new Intl.NumberFormat("en", { style: "unit", unit: "kilometer-per-hour" }).format(88);
// "88 km/h"
new Intl.NumberFormat("en", { notation: "compact" }).format(1_200_000);
// "1.2M"
Enter fullscreen mode Exit fullscreen mode

5. URLSearchParams → delete query-string (−4 KB)

const params = new URLSearchParams({ page: "2", sort: "new" });
params.append("tag", "webdev");
params.toString();  // "page=2&sort=new&tag=webdev"

const q = new URLSearchParams(location.search);
q.get("page");      // "2", correctly decoded
Enter fullscreen mode Exit fullscreen mode

Handles encoding and repeated keys. (It does not do qs-style nested objects — see Gotchas.)

6. navigator.clipboard → delete clipboard.js (−2.5 KB)

await navigator.clipboard.writeText("Copied!");
Enter fullscreen mode Exit fullscreen mode

One line, returns a Promise. Secure context required, and it must run from a user gesture (a click handler).

7. <dialog> → delete your modal library (−5 KB)

Focus trap, backdrop, Esc-to-close, focus restore — all native:

<dialog id="confirm">
  <form method="dialog">
    <p>Delete this item?</p>
    <button value="cancel">Cancel</button>
    <button value="ok">Delete</button>
  </form>
</dialog>
Enter fullscreen mode Exit fullscreen mode
const dialog = document.getElementById("confirm");
dialog.showModal(); // focus trap + ::backdrop + Esc, all free
dialog.addEventListener("close", () => console.log(dialog.returnValue)); // "ok" | "cancel"
Enter fullscreen mode Exit fullscreen mode

8. IntersectionObserver → delete lazy-load / infinite-scroll libs (−4 KB)

const observer = new IntersectionObserver((entries) => {
  for (const entry of entries) if (entry.isIntersecting) loadMoreItems();
}, { rootMargin: "200px" }); // fire before it's visible

observer.observe(document.querySelector("#sentinel"));
Enter fullscreen mode Exit fullscreen mode

Same API powers lazy images, infinite scroll, and scroll animations — off the main thread.

9. ResizeObserver → delete element-resize libraries (−2 KB)

Element-level resize reactions without polling or window.resize hacks:

const ro = new ResizeObserver((entries) => {
  for (const entry of entries) {
    entry.target.classList.toggle("is-narrow", entry.contentRect.width < 400);
  }
});
ro.observe(document.querySelector(".card"));
Enter fullscreen mode Exit fullscreen mode

For pure styling, CSS container queries now cover a lot of this too.

10. AbortController → delete axios cancel tokens (−13 KB)

fetch covers most of what people import axios for — including cancellation and timeouts:

// Cancel a stale request
const controller = new AbortController();
fetch("/search?q=native", { signal: controller.signal });
controller.abort();

// Timeout in one line — no wrapper library
const res = await fetch("/slow", { signal: AbortSignal.timeout(5000) });
Enter fullscreen mode Exit fullscreen mode

Lightning round: 3 more one-liners (−4 KB total)

Object.groupBylodash.groupBy:

const byType = Object.groupBy(files, (f) => f.type); // { image: [...], pdf: [...] }
Enter fullscreen mode Exit fullscreen mode

EventTarget + CustomEventmitt / tiny emitter libs:

const bus = new EventTarget();
bus.addEventListener("login", (e) => console.log(e.detail.user));
bus.dispatchEvent(new CustomEvent("login", { detail: { user: "Ada" } }));
Enter fullscreen mode Exit fullscreen mode

matchMedia → media-query libs:

const mq = matchMedia("(min-width: 768px)");
mq.addEventListener("change", (e) => console.log(e.matches ? "desktop" : "mobile"));
Enter fullscreen mode Exit fullscreen mode

Gotchas: when NOT to reach for the native API

Native isn't a drop-in every time. The honest caveats:

  • Intl.RelativeTimeFormat doesn't do the math. It formats a value+unit you give it — it won't compute "how long ago" or auto-pick the unit. That's why #3 ships a helper. If you have dozens of relative-time formats with fuzzy rules, a 2KB lib may still earn its place.
  • URLSearchParams is flat. No qs-style nested/bracket parsing (?filter[status]=open&tags[]=a). Deep query objects → keep qs.
  • structuredClone drops the un-cloneable. Functions, DOM nodes, class prototypes (you get a plain object back), and getters/setters don't survive. It's for data, not live instances.
  • Object.groupBy and AbortSignal.any() are the newest here — Baseline, but only since 2024 (Safari 17.4+, recent Chrome/Firefox). If you support older browsers, feature-detect or polyfill these two specifically.
  • Clipboard & UUID need a secure context; clipboard also needs a user gesture. Fine in prod, annoying on plain-HTTP dev boxes.

The tally

Deleted ~KB gzipped
moment * 72
axios 13
lodash (clonedeep + groupBy) 7
modal lib 5
lazy-load lib 4
query-string 4
numeral.js 3.6
clipboard.js 2.5
resize lib 2
emitter + media-query libs 2
uuid 1
Total ~115 KB

* 72 KB = moment's default all-locales bundle; ~18 KB core-only. Even at core-only, it's a dependency you no longer need.

All KB figures are gzipped, sourced from bundlephobia.com (Aug 2026) — audit any of them yourself.

That's ~115 KB of gzipped JavaScript your users no longer download — and 11 fewer things in npm audit. Before your next npm install, spend 60 seconds asking the 2026 question: did the platform already ship this at Baseline? More often than not now, it did.

Which of these are you deleting first — and which lib do you think still earns its spot in package.json in 2026? Drop it in the comments.

Top comments (0)