Hide Web Elements Pro — Plugin API

Requires Hide Web Elements Pro 25.1+ (this document describes 26.4). A plugin is a normal userscript that registers itself with the main script. It runs alongside it, and users manage plugins in the ⿻ Plugins tab.

The host now reports plugin API 2 (ctx.host.api, HWEPro.apiVersion). A plugin's api field is the minimum API it needs, so plugins that declare api: 1 keep working unchanged. Everything added after the first release is optional. To check for a newer feature, use ctx.host.features (e.g. ctx.host.features.includes('update-check')). Current features: settings, bus, expose, commands, timers, listen, observe, confirm, navigate, requires, export, network-control, update-check.

Quick start

  1. Install Hide Web Elements Pro 25.1+.
  2. Install a plugin userscript (start from HWE-Plugin-Template.user.js).
  3. Reload the page. You get a toast saying a new plugin was detected. Reload once more and it loads. It appears in Control → ⿻ Plugins.

Plugin header: use @grant none so the plugin and the main script share the page's window. Install order doesn't matter.

const plugin = { id: 'my-plugin', name: 'My Plugin', version: '1.0.0', api: 1, setup(ctx) { /* ... */ } };
if (window.HWEPro) window.HWEPro.register(plugin);
else (window.__HWEPluginQueue = window.__HWEPluginQueue || []).push(plugin);

Only the top frame has the panel and dock, so start with if (window.top !== window) return;.

The window.HWEPro object

The host exposes a small object for plugins and other scripts: register(def), unregister(id), list() ([{ id, name, version, author, status, error, latest }], where latest is the newer version when an update is available), has(id) (true when that plugin is running), isReady(), features, apiVersion and hostVersion. Use register as shown above; the rest is read-only information.

Plugin definition

Field Notes
id Required. 2–40 chars of a-z 0-9 - _. Registering the same id again replaces the old copy.
setup(ctx) Required. Runs when the plugin starts. May return a cleanup function, or a Promise of one.
name, version, author, description, icon Shown in the Plugins tab.
homepage Optional http(s) link shown in the Plugins tab. A Greasyfork script page here is also used to find the plugin's update address.
updateUrl, installUrl Optional http(s) links for update checking and re-installing. updateUrl may be the .meta.js or the .user.js address (updateURL, downloadUrl and downloadURL spellings also work). Greasyfork links are best, because the host can then also recognise the plugin in Get more (see Plugins that only run on some sites).
settings Optional list of settings the host draws for you (see Settings).
requires Optional list of plugin ids that must be running first, e.g. ['other-plugin']. Until then the plugin shows Waiting and starts automatically when they are ready. If a required plugin stops, this one stops too.
api Plugin API version you need. If it is higher than the host's, the plugin is refused with a message.

Renaming. The id is the key for a plugin's saved settings, storage, on/off state and site list. Change name, description and the userscript @name freely, but keep the id if users should keep their data. Changing @name makes most userscript managers treat the file as a new script, so tell users to remove the old one.

If setup throws, only that plugin stops. The error is shown in the Plugins tab and as a toast.

ctx reference

UI

Settings

Declare settings once and the host draws them in your plugin's ⚙ Manage panel, saves them, and gives you a Reset settings button for free.

settings: [
  { key: 'enabled', type: 'toggle', label: 'Enable thing', default: true },
  { key: 'size',    type: 'number', label: 'Size', min: 1, max: 10, default: 3 },
  { key: 'mode',    type: 'select', label: 'Mode', options: ['fast', { value: 'slow', label: 'Slow & careful' }], default: 'fast' },
  { key: 'name',    type: 'text',   label: 'Name', placeholder: 'Anything' },
]

Types: toggle, text, textarea, number (min/max/step), select (options), color (#rrggbb). Each can have desc for a small hint. Define them in the plugin object, or at runtime with ctx.settings.define(list).

Settings survive Clear data (that only wipes ctx.storage). Uninstall removes both.

Features

Helpers that clean up after themselves (stopped automatically on disable, site-block or uninstall)

Errors thrown inside these callbacks are caught, stop nothing else, and are listed under Recent errors in ⚙ Manage.

Working with other plugins

Notifications

The host tells the user about plugin changes with toasts:

Managing plugins (⿻ Plugins tab)

The tab has three views: Installed, Get more and Settings.

Installed

At the top:

Each plugin has:

Below the list, Installed · runs on other sites shows plugins that are installed but limited to other sites (see below). Uninstalled plugins sit at the bottom with a Restore button.

Get more

Lists the plugins and userscripts published by the author on Greasyfork, with install counts, ratings and versions. You can filter by All / Plugins / Userscripts, by Any / Installed / Not installed, and search by name. Installed plugins show a DETECTED tag and an Installed ✓ button. Install opens the script in the user's userscript manager, which asks for confirmation.

Settings

Updates

The host looks up each plugin's update address and compares its @version with the running version. It tries, in order: the plugin's updateUrl/downloadUrl, an @updateURL / @downloadURL line or Greasyfork link found in the plugin's own definition or script, and finally a match by name on the author's Greasyfork page. Checks run about every 6 hours (and again an hour after a failure), when a page becomes visible, or when the user presses ⟳ Check updates. If a plugin has network access switched off, its update check is skipped.

To make updates reliable, give your plugin a Greasyfork updateUrl (or homepage), and keep version in the plugin object equal to the @version in the userscript header.

Plugins that only run on some sites

A plugin whose userscript has a narrow @match (for example only google.com) only registers on those sites, so on any other page the host never sees it. To keep such plugins visible:

Lifecycle

Layering: keeping toasts and popups above the main menu

The main panel sits at z-index: 2147483645. Anything of yours that needs to appear over it must sit higher, or it shows behind the menu.

Following the HWE Pro theme

The panel and dock follow the theme the user picked in Theme (dark, light, midnight, accent color, tint, radius, text size). A plugin can follow it too. How depends on where the UI lives.

1. Panel UI (tabs, dock buttons, ctx.addStyle)

This already inherits the theme. Use the built-in classes, and for anything custom use HWE Pro's CSS variables with a fallback, so the style still works if a variable is missing:

ctx.addStyle(`
.my-card{background:var(--hx-surface,rgba(8,14,25,.78));border:1px solid var(--hx-line,rgba(148,163,184,.14));
  border-radius:var(--hx-radius,14px);color:var(--hx-text,#e7eef8)}
.my-card small{color:var(--hx-muted,#718096)}
.my-card .go{background:var(--hx-cyan-strong,#38bdf8)}
`);

Variables defined on the panel root (names as of 25.3; they are not part of the versioned API, so always give a fallback):

Variable Meaning
--hx-bg Opaque base background
--hx-panel, --hx-surface, --hx-surface-2 Translucent panel and card backgrounds (rgba)
--hx-line, --hx-line-bright Subtle and bright borders (rgba)
--hx-text, --hx-muted Main and secondary text
--hx-cyan, --hx-cyan-strong Accent colors. They shift with the user's accent color
--hx-blue, --hx-violet, --hx-green, --hx-red, --hx-gold Status and highlight colors
--hx-radius Corner radius

Light mode, accent color, tint and border settings are applied to these values by the host, so reading them gives the themed result.

2. Overlays on the page (chips, popups, sheets)

The panel lives in a closed shadow root. Its variables do not reach your page overlays, and document.querySelector or getComputedStyle(document.documentElement) will not find them. To follow the theme:

  1. Get an element that is inside the panel: the el of a dock button from ctx.addDockButton, or the root passed to your tab's render.
  2. Read the variables from that element with getComputedStyle.
  3. Copy them onto your overlay as your own CSS variables (on the host element, so they inherit into your shadow root) and write your CSS against those.
  4. Cache the values in ctx.storage. The panel may not be mounted on every page load, and the cache gives you the last known theme.
  5. Poll while your overlay is visible. HWE Pro has no theme-change event for plugins, so use ctx.setInterval and compare with the last values.
const NAMES = { bg: '--hx-bg', fg: '--hx-text', mu: '--hx-muted', bd: '--hx-line-bright', ac: '--hx-cyan-strong', rad: '--hx-radius' };
let last = '';

function readTheme(probe) {
  if (!probe || !probe.isConnected) return null;
  const cs = getComputedStyle(probe);
  const t = {};
  for (const k in NAMES) t[k] = cs.getPropertyValue(NAMES[k]).trim();
  return t.bg && t.fg ? t : null;
}

function applyTheme(host, t) {
  host.style.setProperty('--bg', t.bg);
  host.style.setProperty('--fg', t.fg);
  host.style.setProperty('--muted', t.mu);
  host.style.setProperty('--line', t.bd);
  host.style.setProperty('--accent', t.ac);
  host.style.setProperty('--radius', t.rad || '14px');
}

setup(ctx) {
  const btn = ctx.addDockButton({ id: 'open', icon: '★', label: 'Mine', onClick() {} });
  const host = document.createElement('div');          // your overlay host
  // ...attach a shadow root, add your overlay, append host to the page...

  const sync = () => {
    let t = readTheme(btn.el);
    if (t) { const sig = JSON.stringify(t); if (sig === last) return; last = sig; ctx.storage.set('theme', t); }
    else t = ctx.storage.get('theme', null);
    if (t) applyTheme(host, t);
  };
  sync();
  ctx.setInterval(sync, 1200);
}

In your overlay CSS, use the copied variables with defaults, for example background: var(--bg, #0b1220); color: var(--fg, #e7eef8); border-radius: var(--radius, 14px).

Tips for theme-following overlays

Notes