The JavaScript features I actually reach for now
Intl for anything a person reads, structuredClone, at(), Object.groupBy, and the platform APIs that replaced dependencies. Plus the number formatting thatβ¦
The useful question about new JavaScript is not "what shipped" but "what can I now delete". These are the ones that removed a dependency or a helper file from my projects.
Intl, which is doing more work than any library I removed
Anything a person reads that involves a number, a date, a currency, a list or a plural should go through Intl. It is built in, it is correct, and it is the single biggest source of quietly wrong output in most applications.
The one that catches everyone:
String(1234) // "1234" β wrong everywhere
new Intl.NumberFormat().format(1234) // "1,234" in en, "1.234" in de
A page that mixes hand-stringified numbers with formatted ones looks broken in every locale β including the one it was written in, because the two appear side by side and disagree.
Then plurals, which is where hand-rolled logic is not merely inelegant but impossible:
// This ternary is not a shortcut, it is a design that cannot be translated.
const label = `${n} ${n === 1 ? 'post' : 'posts'}`;
// Intl.PluralRules knows English has 2 forms, Polish 3, Arabic 6.
new Intl.PluralRules(locale).select(n); // 'one' | 'few' | 'many' | 'other' | ...
The ternary happens to cover English. No ternary can express Arabic, and by the time you find that out the pattern is in four hundred places.
Also worth knowing: Intl.RelativeTimeFormat for "2 days ago", Intl.ListFormat for "a, b and c", and Intl.DateTimeFormat for everything a date library was doing at display time. I still use a date library for arithmetic. Formatting is the platform's job now.
structuredClone
const copy = structuredClone(original);
A real deep clone, built in, handling Date, Map, Set, typed arrays and cyclic references. It replaced the JSON.parse(JSON.stringify(x)) trick, which silently drops functions and undefined, turns Date into a string, and throws on a cycle. That trick was in every codebase I have ever worked on and it was a bug in most of them.
at(), and the end of a small annoyance
items[items.length - 1] // before
items.at(-1) // now
Small, and it removes an off-by-one you can write while tired. Works on strings too.
Object.groupBy
const byYear = Object.groupBy(posts, (p) => new Date(p.publishedAt).getFullYear());
This one deleted a helper from four of my projects β every one of which had its own slightly different groupBy, and one of which handled an undefined key differently from the rest.
Platform APIs that replaced packages
crypto.randomUUID() β a proper UUID, no dependency. Secure-context only, which is the one thing to check.
- The Web Crypto API β real hashing and encryption. I use it to encrypt tokens at rest rather than shipping a crypto library into a browser bundle.
AbortController β cancel a fetch, and it works for event listeners and observers too, which is the underused half.
IntersectionObserver β lazy loading, infinite scroll, scroll-spy for a table of contents. It replaced every scroll-handler-with-a-throttle I ever wrote, and it does not fire on the main thread on every pixel.
navigator.clipboard β with the important caveat that it rejects rather than throwing synchronously, and is undefined outside a secure context. Both paths must report failure honestly, because a false success tick is worse than no feedback: the person pastes whatever was in the clipboard before.
The one I use most and would defend hardest
Not new, but underused: satisfies in TypeScript, paired with as const. It gives you literal types and checking at the same time, so a typo in a table of navigation entries fails at the declaration rather than becoming a broken link three files away.
CSS took over jobs JavaScript used to do
Not JavaScript features, but they belong in the same accounting, because each one deleted code from my projects.
Container queries are the big one. A component that adapts to the width of its container rather than the viewport is a component that works in a sidebar and in a full-width layout without knowing which it is in β which is what every design system wanted and what viewport media queries could never express. It removed a real amount of resize-observer plumbing from my component library.
Logical properties β margin-inline-start rather than margin-left, text-align: start rather than left β cost nothing to adopt and mean right-to-left support is a language setting rather than a rewrite. I use them everywhere now, even where no second language is planned, because the alternative is auditing every stylesheet later.
:has() removed a category of class-toggling: styling a card because of what is inside it, or a label because its input is invalid, used to require JavaScript adding a class and remembering to remove it.
prefers-reduced-motion, prefers-color-scheme and color-scheme mean the browser tells you what the person wants, and honouring it is a media query rather than a settings screen.
The habit, rather than the list
The list above will be out of date. The habit will not: before adding a dependency, check whether the platform does it, and check again in a year for the ones you already added.
I have removed four dependencies from projects this year purely by re-checking, and each removal is permanent β one fewer package to audit, to update, to have a breaking change in, and to eventually migrate away from when it is abandoned. A dependency is a subscription, and the platform is the part that never sends an invoice.
What I still reach for a package for
Date arithmetic across timezones β Temporal is not universally available yet and the edge cases are genuinely hard. Rich text, because a document model is a real problem. Charting, where I use D3 rather than a chart component library, because the customisation always arrives eventually.
Everything else, I check the platform first now. The list of things that genuinely need a dependency has got noticeably shorter, and every one removed is one fewer thing to keep current.
Two things I check before adopting anything
First: does it work in the browsers my users actually have? Not the ones in the compatibility table β the ones in this product's own analytics. For products that ship as an Android WebView, the answer is bounded by the system WebView on devices several years old, which lags the desktop browsers by a noticeable margin.
Second: what happens when it is missing? A formatting API degrading to a slightly less pretty date is fine. A storage API missing and silently discarding a write is not, and the difference is whether the failure is visible. Anything whose absence fails silently gets an explicit check rather than optimistic use, because the alternative is a bug that only exists on hardware I do not own.
Neither question is exciting, and between them they have stopped more production problems than any feature in this post has solved.
https://aoneahsan.com/blog/modern-javascript-2026-updates