close

DEV Community

Cover image for 9 Things You’re Overengineering (The Browser Already Solved Them)
Sylwia Laskowska
Sylwia Laskowska

Posted on

9 Things You’re Overengineering (The Browser Already Solved Them)

Native voice input and idle task APIs

I love writing philosophical essays — thoughts about code, work, all that stuff. I also love deep technical dives. But I know you love my lists of cool features that not everyone has heard about yet 😄

What’s up with me? This week I’m preparing for a conference, fighting performance issues, and trying to get at least somewhat ready for the upcoming holidays 😉

Something nice happened too. I enjoy writing — not just technical articles, but in general. Last summer my life changed quite a bit, and to keep my sanity I started writing a sci-fi story, which I submitted to a Polish science fiction foundation competition. I didn’t win, but my story made it pretty far — around 13th place out of 179 submissions. Considering it was my first attempt at this kind of writing… it could have gone worse 😄

And speaking of sci-fi — the kind happening right in front of us 😉 Today I’ve prepared a batch of things the browser can already do, which honestly didn’t fit in my head not that long ago. A lot of these are still not that widely known, and yet many of them are already supported across modern browsers. Have fun!


1. “Let me just run this later” → requestIdleCallback

At first I thought this API was pointless. It basically lets you run some code when nothing interesting is happening. Ok… cool… but why would I care?

Turns out — there are tons of use cases. For example, collecting data about how the user behaves on your page — definitely not something you want to do while your 200 components are rendering 😅 Or loading less important data, preprocessing something, generating images in the background.

Honestly, there are probably as many use cases as there are developers.

function trackUserScrolling() {
  console.log("User scrolled. This changes everything.");
}

if ("requestIdleCallback" in window) {
  requestIdleCallback(trackUserScrolling);
} else {
  setTimeout(trackUserScrolling, 0);
}
Enter fullscreen mode Exit fullscreen mode

Support: modern browsers (historically missing in Safari, so fallback is still a good idea)


2. “Why is my input not highlighting???” → :focus-within

It’s easy to style an element that has focus. But what if you want to style the parent div? For example, make it pink, add some flowers 😉 You can write 40 lines of JavaScript… or just use :focus-within.

Works. No listeners. No bugs. No suffering.

.form-field {
  border: 1px solid #ccc;
  padding: 12px;
}

.form-field:focus-within {
  border-color: hotpink;
}
Enter fullscreen mode Exit fullscreen mode
<div class="form-field">
  <input placeholder="Type something meaningful..." />
</div>
Enter fullscreen mode Exit fullscreen mode

Support: basically everywhere that matters


3. “Let’s show offline mode” → navigator.onLine

Have you ever built a PWA? Because I have, and the eternal problem is what to do when the user loses connection (e.g. they’re in the wilderness or just walked into an elevator 😄). You can write a bunch of complicated ifs, or just listen to offline and online. On offline you can store data in IndexedDB, and when the user is back online, send it to the server.

window.addEventListener("offline", () => {
  alert("You are offline. Time to panic.");
});

window.addEventListener("online", () => {
  alert("You're back. Panic cancelled.");
});
Enter fullscreen mode Exit fullscreen mode

Support: widely supported (but “online” ≠ “your backend works” 😅)


4. “Smooth animation, but make it cursed” → requestAnimationFrame

We’ve all seen this:

setInterval(() => {
  element.style.left = Math.random() * 100 + "px";
}, 16);
Enter fullscreen mode Exit fullscreen mode

You can feel this is not the best idea 😉 It just lags. Luckily we have requestAnimationFrame, which is synced with the browser repaint cycle, so things are actually smooth.

function animate() {
  element.style.transform = `translateX(${Date.now() % 300}px)`;
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
Enter fullscreen mode Exit fullscreen mode

Support: everywhere


5. “This card should adapt… but only here” → container queries

This feature feels almost unfair. I’m at a point in my career where I barely write CSS anymore (well, except for occasional moments like the one I described here: Is learning CSS a waste of time in 2026?).

But there was a time when I wrote a lot of it. And wow — how much I would have given to apply media queries to a specific element instead of the whole viewport. Now we finally can. The component becomes self-aware, and we can go grab a coffee.

.card-wrapper {
  container-type: inline-size;
}

.card {
  display: grid;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: 1fr 2fr;
  }
}
Enter fullscreen mode Exit fullscreen mode

Support: modern browsers (add fallback if needed)


6. “Random ID, what could go wrong?” → crypto.getRandomValues

const id = Math.random().toString(36).slice(2);
Enter fullscreen mode Exit fullscreen mode

This is how bugs are born. It looks like “good enough” crypto from AliExpress and works… until it doesn’t. First of all, it depends on the engine implementation — we don’t really know what’s happening under the hood. Some patterns are absolutely possible, and with enough IDs you’re basically asking for duplicates.

Luckily, we now have a simple native solution. It’s not a silver bullet, but crypto.getRandomValues is pretty solid — much better entropy, no weird patterns, dramatically reduces the chance of collisions. The browser just does it properly.

const bytes = new Uint8Array(8);
crypto.getRandomValues(bytes);

const id = Array.from(bytes)
  .map(b => b.toString(16).padStart(2, "0"))
  .join("");

console.log("Secure-ish ID:", id);
Enter fullscreen mode Exit fullscreen mode

Support: widely supported


7. “We need a modal” → <dialog>

It’s honestly nice that browsers finally stepped up and said: fine, here’s your modal 😄 No more installing 12KB libraries just to open a dialog that users love so much. This one is also accessible by default, so win-win.

<dialog id="modal">
  <p>Are you sure you want to deploy on Friday?</p>
  <button onclick="modal.close()">Cancel</button>
  <button onclick="alert('Good luck 😬')">Deploy</button>
</dialog>

<button onclick="modal.showModal()">Open modal</button>
Enter fullscreen mode Exit fullscreen mode

Support: modern browsers


8. “Voice input would be cool…” → Speech API

Are you already installing transformers.js because you need speech recognition? Relax — turns out the browser has something for that too. Well… at least Chromium does 😄 So if you can “encourage” users to use Chrome, Edge, or something similar, you’re good. Personally, I’d still be careful with production use, but for demos? Why not.

const SpeechRecognition =
  window.SpeechRecognition || window.webkitSpeechRecognition;

if (SpeechRecognition) {
  const recognition = new SpeechRecognition();

  recognition.onresult = e => {
    console.log("You said:", e.results[0][0].transcript);
  };

  recognition.start();
}
Enter fullscreen mode Exit fullscreen mode

Support: mostly Chromium


9. “Will this CSS explode?” → @supports

Here’s a modern solution to the classic “it works on my machine” — at least in CSS 😉 You don’t have to guess whether something will break your layout. Just wrap it in @supports. There is a small catch — while support is very good, it’s not literally everywhere, so ironically… we could use @supports for @supports.

.card {
  background: white;
}

@supports (backdrop-filter: blur(10px)) {
  .card {
    backdrop-filter: blur(10px);
    background: rgba(255, 255, 255, 0.6);
  }
}
Enter fullscreen mode Exit fullscreen mode

Support: very good


⚠️ But don’t get me wrong

Libraries are great. Sometimes you absolutely need them. But sometimes… you’re installing a dependency for something the browser solved years ago. Before installing anything, just ask yourself (or Google): “Is the browser already smarter than me here?” Sometimes the answer is yes. And that’s… perfectly fine 😄

Top comments (99)

Collapse
 
the_nortern_dev profile image
NorthernDev

Casually mentioning that you almost won a national sci-fi competition right before diving into native browser APIs is an incredible flex. I am genuinely impressed by that combination of skills. 🥳

The technical list is spot on. The amount of heavy dependencies I have seen installed just to replicate that exact native dialog behavior is depressing. Also, your offline mode panic alert logic is exactly the kind of architecture the web needs more of.

Good luck with the conference this week. Try not to let the performance issues keep you up writing code all night. We both know exactly where that leads. Get some actual rest before the holidays, and let me know how the presentation goes. 😃

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Haha, of course my first reaction was: “well… that’s a failure” because it wasn’t one of the top spots 😄 But after a moment I was like… hmm, maybe that’s actually not bad at all 😄

And thank you! The conference is exactly a week from now, so it’s the final stretch now!

Collapse
 
the_nortern_dev profile image
NorthernDev

Only a developer could beat out over a hundred and sixty other writers on their very first attempt and instinctively classify it as a failure. That exact brand of relentless perfectionism is probably why your technical work is so solid, but you have to admit it is a completely ridiculous standard to hold yourself to. You should absolutely just own that success. 😄

​Good luck with the final stretch of preparations this week. Just try to resist the urge to rewrite your entire presentation the night before. By the way, is the conference going to be streamed anywhere? Let me know if there is a link. I would really like to tune in and watch you present.😊

Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

Haha, you’re probably right about that 😄

As for the conference, it most likely won’t be streamed live, but it should be uploaded to YouTube afterward, so I’ll definitely share the link once it’s out! 😊

Collapse
 
pengeszikra profile image
Peter Vivo

Wow the times os going ower my head, I don't know about voice input is aviable in browser.
( my Mac is know that by douple press fn by default)

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Haha yeah, it’s one of those features that feels a bit like sci-fi creeping into everyday life 😄
You’re right though, the support is still a bit limited and not something you’d rely on everywhere in production yet. But things like what you mentioned on macOS show exactly where this is heading.
Feels like we’re slowly moving toward voice being just another normal input method in apps 👀

Collapse
 
leob profile image
leob

Cool article, but this is only the tip of the iceberg - the native browser/web APIs have become so extensive, most devs know only a tiny bit of what's available (to a large extent because they use frameworks like React to program the frontend) ...

What do you think of the idea (and feasibility) to not use React or other frameworks to build a frontend, but only "custom elements" (the preferred contemporary name for "web components", I've learned) and native browser APIs - is it a realistic alternative?

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

That’s a great question!

If I had to answer quickly, I’d say: probably not as a full replacement in most cases. Frameworks solve a lot of problems for us, they come with mature ecosystems, component libraries, state management patterns, routing, etc. So they’re not bad at all. The real issue is more that developers tend to overdo it with additional libraries on top of them.

That said… I’ve actually been thinking about this more recently, and I’m not so sure anymore, especially for simpler apps. With custom elements and modern browser APIs, you can go surprisingly far without a framework. So maybe it’s not about replacing frameworks entirely, but being more intentional about when we actually need them.

Collapse
 
leob profile image
leob • Edited

Great take, excellent - this:

"Maybe it’s not about replacing frameworks entirely, but being more intentional about when we actually need them"

That's exactly the gist of this article which I just came across:

blog.logrocket.com/anti-frameworki...

So yeah, native web APIs and 'custom elements' are not the holy grail, neither are frameworks - each has its place ...

And this one:

"The real issue is more that developers tend to overdo it with additional libraries on top of them"

Yes, we're way too 'easy'/lazy pulling in tons of dependencies even when we don't really need them, also for trivial things - which has drawbacks, and risks:

a16z.news/p/et-tu-agent-did-you-in...

But, if you rely on AI coding tools/agents - they tend to favor ... React:

dev.to/krunal_groovy/vue-vs-react-...

So you need to make a conscious choice, and maybe you need to put in a little bit more effort ...

Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

Wow, that’s a lot of great content, saved! 🙌

As for preferring React, that doesn’t surprise me at all. It’s simply the most popular, so AI was probably trained on it the most. And of course, it’s often a good choice — I like React too, but not always.

At work, for my large enterprise project, we use Angular — and I really appreciate it. It’s stable, a lot of things work out of the box, and I’ve been blissfully avoiding vulnerability dramas for years 😄

That said, I do worry a bit that with AI we’ll see less actual thinking and more defaulting to whatever is suggested. I’m a bit afraid we’ll end up with very “cemented” tech choices. I’ve actually been meaning to write a post about this for a month now… but haven’t found the time yet 😅

Thread Thread
 
leob profile image
leob • Edited

Thanks! Yes that's my fear as well, that everything will a bit more "canned" and run-of-the-mill !

I am seriously of the opinion, among all the AI "hype", that it wouldn't be a bad thing if some development is still done "the old-fashioned way", if only as an antidote, or no, let me make that more specific:

  • some code is just fun to write, so why not write it your self?
  • keep the old craft alive, for yourself and for mankind
  • create code/patterns which can serve as a good (or preferred) "templates" for AI to copy - and 'original' material for AI models to be trained on!
  • and to use or 'promote' different ways of doing something, including using other frameworks than the dominant ones
Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

These are really great ideas 🙌 I especially like the angle of keeping the “craft” alive — not everything has to be automated, some things are just genuinely fun to build.

And your last point actually reminded me of something a friend of mine does. She noticed that AI can sometimes go in completely the wrong direction, so now she always asks it to provide not just one solution, but also 2–3 alternatives. It’s surprisingly effective.

I’ve had similar situations myself — the LLM would suggest adding 10 files and building some complex structure, and when I asked “can this be simpler?”, it suddenly turned out that… yes, it can, and it’s just one extra line 😄

Thread Thread
 
leob profile image
leob

"now she always asks it to provide not just one solution, but also 2–3 alternatives" - nice one, need to remember that!

Collapse
 
apex_stack profile image
Apex Stack

The <dialog> one hits hard. I recently audited a site where the modal library alone added 14KB gzipped to the bundle — for something the browser does natively with better accessibility out of the box.

The loading="lazy" point is especially relevant for anyone running image-heavy pages at scale. I manage a site with thousands of pages across 12 languages and switching from a JS lazy-loading library to native loading="lazy" shaved ~200ms off LCP on mobile. That's the kind of win that directly impacts Core Web Vitals scores.

Would love to see a follow-up on native CSS features that replace JS too — scroll-snap, container queries, and @layer have quietly eliminated a lot of JS-heavy patterns.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks a lot! 🙌 And that CSS-focused follow-up is a great idea, there’s definitely a lot to explore there 😄

Collapse
 
apex_stack profile image
Apex Stack

Right? The CSS side is where most of the hidden bloat lives. I've seen projects pulling in entire utility frameworks just for a handful of layout patterns that grid and has() handle natively now. Would love to see someone benchmark the real-world performance delta between CSS-native approaches and popular UI kits.

Thread Thread
 
sylwia-lask profile image
Sylwia Laskowska

Haha true, that would be super interesting to see 😄 I’d love to see real numbers comparing CSS-native approaches vs full UI kits in real-world apps.

Thread Thread
 
apex_stack profile image
Apex Stack

Would be a fascinating benchmark! On one of my projects I went Tailwind-only (no component library) for a data-heavy site with 100K+ pages — the CSS output is surprisingly small because utility classes deduplicate naturally at scale. The entire site ships under 30KB of CSS gzipped.

The hidden cost with full UI kits isn't just bundle size though — it's the cascade of JavaScript that comes with interactive components you probably don't need. A datepicker here, a modal there, and suddenly you're shipping 200KB of JS for what's essentially a static content site.

Would love to see someone do a Lighthouse comparison: same layout built with Tailwind vs MUI vs Chakra. My bet is the Tailwind version wins on CLS and LCP by a noticeable margin on mobile.

Collapse
 
jon_at_backboardio profile image
Jonathan Murray

The requestIdleCallback example is a good opener — it's one of those APIs that solves a real problem (deferring non-critical work without blocking the main thread) that most developers reach for a setTimeout hack to approximate.

A few others worth adding to the "browser already solved it" list: the Intersection Observer API (replaces hand-rolled scroll listeners for lazy loading and animation triggers), the View Transitions API for page transition animations that most people build with JavaScript frameworks, ResizeObserver for element-level resize detection (no more polling or window resize hacks), and dialog element with showModal() for accessible modals without a single line of focus-trap JavaScript.

The pattern across all of these is the same: they exist because the browser vendors watched what developers were hacking together repeatedly and standardized the good version. The bottleneck is usually awareness — most developers don't audit their dependencies against the platform periodically. Worth doing annually.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Exactly this 🙌 I’ve actually written about some of these in my previous articles — things like Intersection Observer or ResizeObserver are such good examples of “the browser already solved it.”

I also really like the idea of doing a yearly audit. That’s honestly something more teams should consider. The problem is, we’re often tied to a specific UI library, and then it’s up to them whether they keep up with modern browser capabilities or not.

And I’ve definitely seen some “genius” cases where datepickers still use Moment.js… even though the Moment docs themselves say not to use it anymore 😄

Collapse
 
alptekin profile image
alptekin I.

again awesome article, Sylwia. thanks
How was your conference, i hope all was as you expected.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks a lot! 😊 The conference is actually this Thursday, so it’s still ahead of me — a mix of excitement and mild terror at this point 😄

Collapse
 
alptekin profile image
alptekin I.

I am sure it will be fine, I would like to read your observations and experience afterwards, if you like.
Good luck and have fun.

Collapse
 
htho profile image
Hauke T.

requestAnimationFrame is great. You probably can skip the Date.now() part. The callback receives a timestamp as the first argument: developer.mozilla.org/en-US/docs/W...

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Good catch, you’re right! Thanks for the clarification 🙂

Collapse
 
itsugo profile image
Aryan Choudhary

Honestly, I'm still wrapping my head around the idea of container queries - it sounds like a total game changer for layout management. Saving this!

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Exactly! 😄 It really is a game changer. Such a shame I barely write CSS anymore these days 😅

Collapse
 
apex_stack profile image
Apex Stack

The requestIdleCallback point really resonated. I run a static site with 100K+ pages built on Astro, and one of the biggest performance wins was deferring analytics and non-critical JS to idle time instead of loading it eagerly. Shaved nearly 200ms off LCP on mobile.

The :focus-within one is also underrated — I used to write custom JS for that exact pattern on form containers. Replacing it with a single CSS pseudo-class was one of those "why didn't I know this earlier" moments.

Curious if you've looked into the Speculation Rules API for prerendering? That's another browser-native feature that replaces a lot of custom prefetching logic and has massive implications for perceived navigation speed.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

That’s a really nice win — shaving ~200ms off LCP just by deferring non-critical work is exactly the kind of improvement that actually matters in real apps 🙌

And yes, :focus-within is one of those “why did I ever write JS for this” moments 😄 I had the same reaction.

As for the Speculation Rules API — I’ve looked into it a bit, but haven’t used it in a real project yet. It definitely feels like another one of those features that can replace a lot of custom logic once it matures. The whole idea of letting the browser handle prerendering heuristics is super interesting. Have you used it in production already?

Collapse
 
apex_stack profile image
Apex Stack

Haven't deployed it in production yet either, but it's high on my list. For a static site with predictable navigation patterns (stock page → sector page → related stocks), the prerender hints would map really cleanly to user intent. The part I'm most interested in is replacing the prefetch-on-hover JS I currently use — letting the browser handle that natively with better resource management feels like the right direction. Definitely one to watch as browser support expands.

Collapse
 
htho profile image
Hauke T. • Edited

I like requestIdleCallback. I read about a pattern you can implement with it: idle-until-urgent:
There are some expensive calculations required for some function the user is likely to invoke. Instead of doing it once it is required, you can do it once you have time for it. Basically pre-caching.
But: when the result is required before the work was done, you cancel the callback and do it just-in-time.

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Exactly this! It’s such a beautiful pattern. Idle-until-urgent really changes how you think about work scheduling in the browser. Instead of “do everything immediately”, it becomes “do it when it makes sense… unless the user needs it now”.
Feels like a small thing, but it actually shifts your whole mental model of what the browser can handle for you today.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.