Evaluate Invoker Commands API (command/commandfor) for Dialog, AlertDialog, and a custom-command bridge
@johnleider is already working on this.
Since Jul 12, 2026.
- Dominant language
- TypeScript
- Stars
- 735
- Forks
- 10
- Avg merge
- 10h 47m
- Merged PRs (30d)
- 72
Description
Summary
The web platform's Invoker Commands API (command / commandfor HTML attributes + CommandEvent) lets a <button command="show-modal" commandfor="id"> declaratively open/close a dialog, toggle a popover, or dispatch a custom --command event to a target — replacing JS onClick wiring, with the UA managing aria-expanded / aria-controls. This issue parks an assessment of where (if anywhere) it earns a place in @vuetify/v0.
Parked for a future release — no milestone.
Counterargument first
Most of v0 already composes the native primitives this API wraps, so the blanket answer is "no":
- Popover already emits
popovertargeton its activator andpopoveron content — the UA toggles it with zero JS.command="toggle-popover"is functionally equivalent to thepopovertargetactionbehavior already in effect. Zero gain. - Custom commands duplicate what
createContext+ context methods (next(),select(),toggle()) already do — but type-safely and without ID coupling. - Constraints cut against v0's grain: the target must exist in the DOM with a resolvable
id, and the invoker must be a real<button>(v0'sasis polymorphic —as="a"would silently break it).
So this is polish, not a composable-layer differentiator. Two exceptions are genuinely worth it.
Ranked opportunities
| Fit | Where | Native command | Value |
|---|---|---|---|
| Strong | AlertDialog | request-close |
High — maps onto hand-rolled prevent-close logic |
| Good | Dialog | show-modal / close |
Medium — dedups JS onClick |
| Novel bet | Carousel / Step / Tabs | custom --next etc. |
Headless novelty (needs design decision) |
| Skip | Popover | toggle-popover |
~Zero (already native) |
| Skip | Tooltip, Snackbar, Collapsible, ExpansionPanel | — | Wrong interaction model / no benefit |
1. AlertDialog request-close (strongest case)
request-close fires a cancelable cancel event; if the consumer preventDefault()s it, the dialog stays open. That is exactly what AlertDialogContent.onCancel hand-rolls today (e.preventDefault(); return), and it's adjacent to the wait() / close() deferred-close pattern in AlertDialogAction. The platform now ships a primitive for the precise "are you sure? / unsaved changes" flow v0 built by hand.
2. Dialog show-modal / close
DialogActivatordoesonClick → context.open()→command="show-modal" commandfor={contentId}DialogClosedoesonClick → context.close()→command="close"
The content id already exists on DialogContent, and PopoverActivator already proves the activator-reads-content-id pattern. Net: less JS, UA-managed aria-* on the invoker.
3. Custom-command → method bridge (novel, needs a design decision)
A headless primitive (working name useInvoker / createCommand) where a component root listens for CommandEvent and routes custom commands (--next, --prev, --select) to context methods — letting a consumer wire any button anywhere in the DOM to a Carousel/Step/Tabs without prop-drilling or shared context. On-brand with v0's "compose native platform APIs into novel composables" identity (cf. usePopover).
[!IMPORTANT]
PHILOSOPHY §2.5 caveat: composables never bind DOM events — components do. So this can't be a raw composable; it needs to be component-layer, or a sanctioned exception like theuseEventListener/ observer wrappers. Decide the boundary in a design doc before building.
Mechanics that keep this low-risk
- Progressive enhancement:
Atomforwards$attrs, and Button/Toggle/Activators usemergeProps— socommand/commandforpass through today without any v0 change. Adoption is additive. - Feature-detect to avoid double-firing (native open + JS
open()): gate on'command' in HTMLButtonElement.prototype; consider aSUPPORTS_INVOKERglobal alongside the existingSUPPORTS_*constants and drop the JS handler whentrue. - Browser support: Chrome/Edge, Safari, and Firefox all shipped
command/commandforduring 2025 — "Baseline newly available," not yet "widely available." Fine for a headless lib doing progressive enhancement; premature to make it the only path.
Proposed tracks
- Additive, feature-detected: adopt
request-closein AlertDialog andshow-modal/closein Dialog behindSUPPORTS_INVOKER, keeping JS handlers as the fallback. Small, defensible. - Design-doc first: the
CommandEventcustom-command bridge — resolve the §2.5 boundary before implementing.
Skip Popover, Tooltip, Snackbar, Collapsible, and ExpansionPanel entirely.
References
- MDN: Invoker Commands API
- Relevant source:
packages/0/src/components/{Dialog,AlertDialog,Popover}/,packages/0/src/composables/usePopover/
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.