← All posts

Windows on the frontend

JS pane: Run-on-demand scripts, no auto-run on every visit

A JustZix JS rule runs automatically when the URL matches. Great for things that should always work — auto-skip cookie banners, custom shortcuts. But some scripts are destructive: "empty cart", "delete email draft", "reset form". You don't want those on auto-run. You want to click ▶ only when you want to. That's a JS pane (v2.13.56+).

Three JS windows — which for what

Window typeWhen it runsUse case
JS ruleAuto on every matching URL loadAuto-skip cookies, custom shortcuts, GTM logger
JS ConsoleEvery Ctrl+Enter = new evalAd-hoc REPL, one-off checks
JS paneOnly on Ctrl+Enter / click ▶Persistent code, destructive actions, bulk ops

A JS pane looks almost like a CSS pane (textarea, draggable, coloured dot), but has an extra ▶ Run button in the header. Code lives in the textarea, never auto-executes — the one exception is resume after reload (if there was something in sessionStorage before F5, JustZix runs it again to restore pre-refresh state).

First use

  1. JustZix options → folder/group/rule → "Windows" → "+ JS pane".
  2. Name: "Empty cart", colour: amber (default #D65D0E).
  3. Visit shop.com/cart. The pane appears top-right with a header ("• Empty cart [▶]") and an empty textarea.
  4. Type:
    document.querySelectorAll('.cart-item .remove-btn')
      .forEach(btn => btn.click());
  5. Ctrl+Enter (or click ▶). All "Remove" buttons clicked.

Dirty state — you visually know there's a change

After typing / editing code, until you run it (or revert to the last-run version), the Run button shows a "dirty" state (with a custom runColor — from v2.13.64 you can pick your own). It's a visual cue: "you have unrun changes".

Click ▶ → code runs, dirty state clears. Revert the textarea to an earlier value → dirty appears again. JustZix compares current content with el.dataset.jzLastRun.

Error overlay — you don't need DevTools open

When eval throws an exception, a red bar appears at the bottom of the pane (.jz-pane-error):

JS error: Cannot read properties of null (reading 'click')

Click ▶ again with fixed code → the error clears. No need to flap F12 open. For async errors (setTimeout(...) throwing) the overlay won't catch them — known limitation, async errors must be tracked via DevTools or JustZix JS Console.

Persistent vs ephemeral — which scenario

JS pane content persists in sessionStorage['jz_pane_{id}_content'] per tab. Consequences:

If you want code permanently (even after closing the tab) — that's not a pane, that's a JS rule. Pane = scratchpad with a Run button.

Use case 1 — state-specific destructive actions

Cleanup in a shop admin panel. Action "Clear all demo products from cart":

// Only runs when you click ▶. Auto-run = disaster.
if (!location.href.includes('/admin/demo')) {
  throw new Error('Only for /admin/demo');
}
const rows = document.querySelectorAll('tr.product');
console.log(`Removing ${rows.length} products...`);
for (const row of rows) {
  await fetch('/api/products/' + row.dataset.id, { method: 'DELETE' });
  row.remove();
}
console.log('Done.');

Defence: URL guard + pane name "CLEANUP DEMO" + amber dot. Hard to do accidentally.

Use case 2 — bulk operations

50 users have to be marked "verified". UI allows click-per-user. JS pane:

const rows = document.querySelectorAll('.user-row:not(.verified)');
let count = 0;
for (const row of rows) {
  row.querySelector('.btn-verify')?.click();
  await new Promise(r => setTimeout(r, 200));  // throttle so the API doesn't yell
  count++;
}
console.log(`Verified ${count} users.`);

One click ▶, 50 users. 200 ms sleep so we don't flood the API. Three times faster than the real bulk endpoint that doesn't exist.

Use case 3 — scripted demo

You're showing a client the "add 3 products + go to checkout + fill test data" flow. 30 seconds each time. A pane script does it all in 2 seconds:

// Demo flow
[1, 2, 3].forEach(i => document.querySelector(`[data-product-id="${i}"] .add-btn`)?.click());
await new Promise(r => setTimeout(r, 500));
document.querySelector('.checkout-btn').click();
await new Promise(r => setTimeout(r, 1000));
Object.entries({
  email: 'demo@example.com', name: 'Demo', address: 'Test 1'
}).forEach(([k, v]) => {
  const el = document.querySelector(`[name="${k}"]`);
  if (el) { el.value = v; el.dispatchEvent(new Event('input', { bubbles: true })); }
});

The client sees an "auto-pilot" flow. Professional. Without typing in real time.

Pitfalls

What's next

JS pane is the 2nd "window on the frontend" type in JustZix. We've previously written about CSS pane (live CSS editor) and JS Console (REPL). The three together are a mini-IDE right inside your browser tab, scoped per domain.

Install JustZix and get Run-on-demand scripts on every page, without the auto-run risk.

Rate this post

No ratings yet — be the first.

Try it yourself

Install JustZix and paste any snippet from this article. Two minutes from zero to a working rule across all your devices.

Get JustZix

Features · How it works · Examples · Use cases