Invoker Commands API

  • html
  • invoker
  • javascript
Oct 16, 2025
More than just opening and closing dialogs!

Introduction

The Invoker Commands API addresses one of the key shortcomings of the HTML Dialog element—opening and closing without client-side JavaScript. It also introduces custom commands allowing developers to create their own actions that can be utilized from the command attribute.

Attributes

The command and commandfor attributes are the main controllers of the Invoker Commands API. The trigger element must have both of these attributes set in order for the command event to fire.

  • command - action to take upon clicking the trigger element, built-in or custom
  • commandfor - id of the target element to execute the action on

As a best practice, also add the type=button attribute to to any buttons that trigger commands to override the default type=submit. This ensures accessibility and proper functionality within <form> elements.

Opening and closing dialogs

The Popover API has enabled developers to create popovers that open and close without the use of client-side JavaScript. The <dialog> element had been left behind until now, developers had to use the HTMLDialogElement.showModal and HTMLDialogElement.requestClose JavaScript methods.

With the Invoker Commands API, you can control dialog visibility without JavaScript. The command attributes mirror the instance methods adapted to kebab-case, for example show-modal and request-close.


<button commandfor="dialog-id" command="show-modal" type="button">
	Show Dialog
</button>

<dialog id="dialog-id">
	<h2>Dialog</h2>

	<p>
		Lorem, ipsum dolor sit amet consectetur adipisicing elit. Magni
		necessitatibus provident, totam vel a hic, numquam molestiae error doloribus
		ab ducimus alias iste incidunt aliquid sint, inventore ea? Nihil,
		perspiciatis?
	</p>

	<button commandfor="dialog-id" command="request-close" type="button">
		Close
	</button>
</dialog>

Dialog

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Magni necessitatibus provident, totam vel a hic, numquam molestiae error doloribus ab ducimus alias iste incidunt aliquid sint, inventore ea? Nihil, perspiciatis?


Popover API methods are also available as values for the command attribute, for example command=show-popover. See the full list of values here.

Custom commands

A powerful feature of the Invoker Commands API is custom commands. It unlocks some new patterns that make writing vanilla JS a bit more declarative. For example, we can switch the background color of the div with a custom --change-color command. Custom commands must be prefixed with --.

<button
	type="button"
	command="--change-color"
	commandfor="content"
	data-color="red"
>
	Red
</button>
<button
	type="button"
	command="--change-color"
	commandfor="content"
	data-color="blue"
>
	Blue
</button>
<button
	type="button"
	command="--change-color"
	commandfor="content"
	data-color="green"
>
	Green
</button>

<div id="content"></div>

Instead of adding an event listener to the <button> elements, it can be added to the content instead. This makes it easy to create different commands for certain components that can be triggered from anywhere in your application via HTML attributes.

content.addEventListener("command", (e) => {
	if (e.command === "--change-color") {
		content.style.backgroundColor = e.source.dataset.color;
	}
});

Self target

If you don’t need a separate target element, you can set the commandfor to target the trigger element with the same id. commandfor is required for the event to fire.

In most cases, if you are targeting the same element, addEventListener is probably a better option.

<button
	command="--custom-command"
	commandfor="self-id"
	id="self-id"
	type="button"
>
	Self Target
</button>

Listening for any command

You can listen for all commands by adding an event listener to document.body with the capture option.

For example, you can log all command events on any element with the following code:

document.body.addEventListener(
	"command",
	(e) => {
		console.log(e);
	},
	{ capture: true },
);

Conclusion

I’m interested to see how developers use this API when it’s supported across browsers. It could be a nice API to create a library of custom commands that users could access simply with HTML attributes.

Thanks for reading!


Edit