DEV Community

Alexandra
Alexandra

Posted on

HTML is getting cool again: Meet the Invoker Commands API

Exposes how LLMs miss modern browser capabilities

For years, frontend development has had a slightly embarrassing relationship with HTML. We all read about semantic HTML, we talk about using the right landmarks, the right attributes, accessible forms, and meaningful elements. And then we go back to writing React.

While the whole industry is obsessed with AI, browsers are shipping features that make the platform even more capable. Features that let us remove JS, reduce state, and express UI behaviour in HTML. But since AI is trained in the past, these are ignored or not recommended enough through old patterns.

State boilerplate to open a dialog

Historically, in order to open a dialog or a popover, we need a chunk of custom boilerplate code.

<button id="open-dialog">Open dialog</button>
<dialog id="my-dialog">
  <p>Dialog content</p>
  <button id="close-dialog">Close</button>
</dialog>

<script>
  const dialog = document.getElementById("my-dialog");
  document.getElementById("open-dialog").addEventListener("click", () => {
    dialog.showModal();
  });
  document.getElementById("close-dialog").addEventListener("click", () => {
    dialog.close();
  });
</script>
Enter fullscreen mode Exit fullscreen mode

We need a button to open our dialog, the dialog itself, and then we write JS to explain the interaction to the browser: "When the user clicks the button, open the dialog".

If you're using React or Vue, this can get even more elaborate: You need some custom state, potentially pass it to your component, wire up an event handler, and then make sure everything stays in sync.

Whether vanilla or framework, the code above is completely reasonable on its own, every frontend developer has written something similar a hundred times. But after writing it for the thousandth time, it made me wonder: do we really need application state to represent that a dialog is open? The answer is: it depends. Sometimes state is needed. But sometimes we're just rebuilding behaviour that HTML and the browser can already provide for us out of the box in 2026.

Enters the chat: the Invoker Commands API

The Invoker Commands API provides us a way to declaratively assign behaviours to buttons, which then allows us to control these interactive elements. Instead of adding an event listener we can describe the relationship directly in HTML.

The attributes that help us are commandFor and command:

  • commandFor: turns our button into a "command invoker". It takes the ID of the element to control as its value.
  • command: Specifies the action to be performed on that element.
<button commandfor="mycoolpopover" command="toggle-popover">
  Toggle the popover
</button>
<section id="mycoolpopover" popover>
  <button commandfor="mycoolpopover" command="hide-popover">Close</button>
  Awesome Popover content
</section>
Enter fullscreen mode Exit fullscreen mode

How to do it in React?

All of these are transferable to your framework of choice:

export function DeleteButton() {
  return (
    <>
      <button command="show-modal" commandFor="delete-dialog">
        Delete account
      </button>
      <dialog id="delete-dialog">
        <h2>Delete account?</h2>
        <p>This cannot be undone.</p>
        <button command="close" commandFor="delete-dialog">
          Cancel
        </button>
      </dialog>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

The important detail here is that React's JSX property is commandFor, while the resulting HTML attribute is commandfor

Is that a really big deal?

At a first glance this looks like saving, maybe 10 lines of code. That's nice. But the most interesting is the shift of the responsibilities from us, back to the browsers.

The browser isn't becoming less capable because we're writing less JavaScript, but rather the opposite. We finally need less JS.

Browser support

Now, before everyone starts deleting their dialogs, there is a small catch: The Invoker Commands API is new. MDN currently lists it as Baseline 2025, with cross-browser availability in the latest browser versions since December 2025. Older browsers may not support it.

References

Top comments (22)

Collapse
 
pawar-shivam7 profile image
Pawar Shivam

This is a really good reminder that the browser platform is evolving faster than a lot of our usual frontend patterns.

The part about LLMs reproducing older JS/React boilerplate is especially interesting. We often reach for state and event handlers before checking whether the platform already has a native solution.

command + commandfor looks like a small API change, but the bigger win is reducing unnecessary UI state and letting the browser own the interaction. Progressive enhancement with a feature-detected fallback also feels like the right approach while support continues to mature.

Definitely adding this to my list of APIs to experiment with. πŸš€

Collapse
 
publiflow profile image
PubliFlow

Good CSS/HTML coverage. The landscape here moves quickly β€” worth noting that container queries and :has() selector support have reached baseline, which can simplify many of the responsive patterns we previously needed JS for.

Collapse
 
ale3oula profile image
Alexandra

Yes this are cool additions, i want to probably write about them too! Too many things to get excited, too little time.

Collapse
 
publiflow profile image
PubliFlow

The struggle of having an overflowing backlog of exciting web platform features is incredibly real. If you do tackle the Invoker Commands API, narrowing the scope to something like custom dialog controls might save you some research time while still delivering high value to your readers. Feel free to reach out if you want to trade notes on the spec before you start drafting.

Collapse
 
jsb-securedme profile image
Jean-Sebastien Beaulieu

thanks you for the knowledge realy interesting

Collapse
 
micaavigliano profile image
Mica

really appreciate a good human-written post! Just useful and straight to the point information!

Collapse
 
hoseinmdev profile image
Hosein Mahmoudi

Tell me about it! Back in the day, we had to attach an event listener to literally everything just to open a simple modal πŸ˜‚

Modern HTML is making web dev so much smoother and less overwhelming for beginners. Loved this update

Collapse
 
promptshereai profile image
Fouad El Mourabit

Nice reminder that browser-native features can replace a lot of UI state. I’d pair this with feature detection and a graceful fallback, since support may vary across browsers.

Collapse
 
celine_carter_f9e7f703c59 profile image
Celine Carter

Absolutely! I think the biggest benefit is reducing unnecessary JavaScript for interactions the browser can already handle. It’s easy to fall back on familiar React patterns, so it’s refreshing to see native APIs getting more capable. Definitely something worth experimenting with. πŸš€

Collapse
 
gridport profile image
GridPort

I see…! Even with coding, learning materials can be outdated, so you can end up learning outdated approaches too. This gave me a new perspective. Thank you!

Collapse
 
whitelab_soft_5075369a169 profile image
WhiteLab Soft

thank you for great post

Collapse
 
roshxn467 profile image
super rosh

tbh html was always cool

Collapse
 
ale3oula profile image
Alexandra

i think you are right! people take it for granted!