DEV Community

Emery Yang
Emery Yang

Posted on

No-JS Modal in 90 Minutes: Spiking the Invoker Commands API

No-JS Modal in 90 Minutes: Spiking the Invoker Commands API

Verdict first: the Invoker Commands API ships today — as progressive enhancement. In Chromium, the dialog below opens with zero JavaScript. Everywhere else, a three-line shim takes over. This post is the 90-minute spike that produced the evidence.

The trend is real. HTML added declarative commands for buttons. command="show-modal" plus commandfor="dialog-id" replaces a click handler. Hot APIs deserve evidence, not hype. A spike produces evidence.

The Hypothesis

One hypothesis. One deadline. Ninety minutes.

A dialog can open, close, and dismiss via pure HTML attributes, with no framework wiring, and still pass a basic accessibility check.

Ship-or-kill criteria:

  1. The dialog opens and closes with JavaScript disabled.
  2. Focus moves into the dialog; Escape closes it.
  3. The non-Chromium fallback stays under 10 lines.

Kill criteria: the API demands a brittle workaround, or the fallback costs more than the markup saves.

Why a Spike Beats a Tutorial

Tutorials show happy paths. Spikes expose constraints. A shiny API looks perfect in a demo. The edge case appears in week three. A spike finds it in 90 minutes.

The Free-Tier Setup

Spikes should not need a purchase order. This one ran on MonkeyCode, an open-source AI coding tool. The free model access drafted the markup and the shim. The free server hosted the test page. Total spend: zero.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The current free tier includes 10 million tokens and a free server option. That is enough for a spike like this one. AI generates markup fast. It also generates plausible-looking but wrong attributes fast. The checklist below catches the second part.

The Artifact

The exact test page. Generate something similar, then verify every attribute by hand. AI drafts; you decide.

<dialog id="confirmDialog">
  <p>Delete this draft? The action is reversible.</p>
  <form method="dialog">
    <button value="cancel">Keep it</button>
    <button value="confirm">Delete</button>
  </form>
</dialog>

<button id="openBtn" commandfor="confirmDialog" command="show-modal">
  Open confirmation dialog
</button>
<button commandfor="confirmDialog" command="close">
  Close
</button>
Enter fullscreen mode Exit fullscreen mode

The HTML attribute is lowercase commandfor. The JavaScript property is camelCase commandFor. Mix them up, and the button silently does nothing. command declares the action. commandfor points to the target id. No addEventListener anywhere in the no-JS path.

The fallback shim. Three lines.

if (!("command" in document.createElement("button"))) {
  document.getElementById("openBtn").addEventListener("click", () => {
    confirmDialog.showModal();
  });
}
Enter fullscreen mode Exit fullscreen mode

Backdrop clicks do not close the dialog automatically. If you want that behavior, check the closedby attribute in your Chromium version. Do that before you claim the modal works exactly like your old one.

The Verification

Deploy the page to the free server. Confirm it is reachable.

curl -s -o /dev/null -w "%{http_code}\n" https://your-free-server.example/invoker-spike.html
Enter fullscreen mode Exit fullscreen mode

Expected: 200. Then run four checks.

  1. No-JS path: open DevTools, disable JavaScript, reload. Click the button. In Chromium, the dialog opens. The markup is the handler.
  2. A11y smoke test: press Tab. Focus lands inside the dialog. Press Escape. The dialog closes. Both are native dialog behaviors, not shims.
  3. Fallback path: open the same page in Firefox or Safari. The shim binds the click. The dialog still opens.
  4. Cost check: count the lines you deleted. The no-JS path is zero lines of JavaScript. The shim is three.

Turn JavaScript back on between checks. A stale DevTools session produces false failures.

Check Method Expected
No-JS open Disable JS, click Opens in Chromium
Focus + Escape Tab, then Esc Native behavior
Fallback Firefox or Safari Shim opens dialog
Code cost Count removed lines Zero-line path, 3-line shim

What this table does not prove: permanent cross-browser support. Re-check MDN browser-compat-data before you commit. Blog posts age. Support tables update.

The Verdict

Ship, with a gate.

  • Use the markup as progressive enhancement.
  • Treat the no-JS path as a Chromium-only bonus today.
  • Keep the shim until the support data changes.
  • Wire the check into your browser matrix, not your roadmap assumptions.

The spike produced a conditional ship. The API works. The fallback is cheap. The gate is browser support.

Who Should Skip This

Three teams should not use this pattern.

  • Teams with "identical in every browser" requirements. The fallback cost erases the savings.
  • Teams with mature imperative dialog systems. Migration is churn, not value.
  • Teams without browser-level tests. A declarative API still ships bugs when the fallback is untested.

The 90-Minute Budget

Steal the schedule.

  1. 0-15: write the hypothesis and criteria.
  2. 15-40: generate markup and shim on the free model tier.
  3. 40-60: deploy the test page to the free server.
  4. 60-90: run the four checks and draft the decision.

Now apply the same budget to your next hot API. The free tier covers this exact spike: 10 million tokens and a free server. If the evidence passes, ship. If not, you lost an afternoon, not a quarter.

Top comments (0)