I've Been Writing Way Too Much JavaScript for Popups

I've Been Writing Way Too Much JavaScript for Popups

Kite Eugine

Kite Eugine • Jan 29, 2026

2:47 AM. I'm debugging why a modal won't close on mobile. Again.

The click-outside handler isn't firing. Or it's firing too early. Or the touch event is doing something weird. I've been down this rabbit hole before. Multiple times. With multiple popups. On multiple projects.

So I do what any developer does at 2:47 AM: I start searching for a library that handles this better. All the choices I’ve made in my life have led me to this moment. Somewhere deep in that search, I stumble onto the MDN docs.

Scrolling through the MDN docs, something caugh my attention. The Popover API!!! Why am I discovering this now? All the suffering...all the wasted hours...

I've been writing the same JavaScript over and over again. Every menu. Every dropdown. Every tooltip. Every command palette. The pattern's always identical: track an isOpen state, add click handlers, handle the Escape key, wrangle focus management, fix accessibility issues, and then... do it all again for the next popup.

Turns out? Browsers have been quietly learning to do this stuff for us. We just weren't paying attention.

Meet the Popover API

The Popover API is one of those features that makes you feel slightly silly for not knowing about it sooner. It lets you create popups with zero JavaScript. No state management. No event listeners. No libraries.

Here's literally all you need:

<button popovertarget="my-menu">Open menu</button>
<div id="my-menu" popover>This is a popover</div>

That's it. I'm not hiding anything.

Click the button? Popover opens. Click outside? It closes. Press Escape? Closes. Focus management? Handled. Screen reader support? Built in.

The browser does everything.

If you want more control over the behavior, just add one attribute:

<button popovertarget="my-menu" popovertargetaction="show">
  Open menu
</button>

You've got three options: show, hide, and toggle. Still no JavaScript required.

Think about what you normally need for a popup:

  • A boolean isOpen somewhere in your state
  • Click handlers to toggle it
  • A keydown listener for Escape
  • Focus trap logic so keyboard users don't get lost
  • ARIA attributes for screen readers
  • All those edge cases QA finds three days before launch

The Popover API handles basically all of that. Out of the box. For free.

You can still enhance it with JavaScript if you need custom behavior. But here's the thing: you're not forced to anymore.

Styling?

A popover is just a normal element. You style it however you want:

[popover] {
  padding: 0.75rem;
  border-radius: 0.75rem;
  background: white;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
}

Want animations? Add them. Need theming? Go for it. Want to use CSS anchor positioning to place it relative to the trigger? Still no JavaScript needed.

It's just CSS CSSing.

What I really like about this API is how it flips the usual development flow:

  • HTML defines the behavior — What happens when you click
  • CSS defines the appearance — How it looks and moves
  • JavaScript becomes optional — Only when you need something custom

And if you're using React, Vue, Svelte, or whatever, this works great with all of them. Instead of managing open/close state in your framework, you let the browser handle the basics and only reach for JavaScript when you actually need it.

This is one of those features that makes you question habits you've been carrying around for years.

If you're building anything for modern browsers, the HTML Popover API is definitely worth your time. It's simpler. It's more accessible by default. And it removes a surprising amount of repetitive code from your projects.

Sometimes the best optimization isn't finding a better library — it's realizing you don't need to write the code at all.

I'm off to sleep now.

Comments (0)

No comments yet. Be the first to comment!

Related Posts