Glossary
Every term this book uses as a term of art, in one alphabetical list. Each entry is a one-line orientation plus the page that owns the term — the rule, the limit and the error string live there, never here. When this page and a linked page disagree, the linked page wins.
Version gates are shown inline, e.g. (0.11.0+), and mean
@homerunner-next/widget-core. Which versions you can actually install is in
Install and versions.
| Term | What it is | Defined in |
|---|---|---|
accepts | Per-slot list of categories and/or exact keywords the dashboard’s slot picker offers. A hint to the customer, read by nothing at render time. | Layout widgets |
| Advisory (unvalidated) | Enforcement level: nothing checks it at any layer, so a typo is yours to find in production. | Limits and error index |
Asset proxy (/p/) | {proxy}/p/{slug}/{dist-relative file} — the versionless plugin asset endpoint. One 302 to the content-hashed CDN file. Never put crossorigin on a /p/ script tag. | Keywords, assets and URLs |
assets.fonts | Stylesheet URLs (or confined relative paths) injected at document level, because @font-face is ignored inside a shadow root. (0.12.0+) | Keywords, assets and URLs |
| Build manifest | dist/manifest.json — generated {buildHash, generatedAt, files} mapping every dist-relative name to its hashed twin. Not the registration manifest. | Keywords, assets and URLs |
| Built zip | The zip the reviewer builds from your source and uploads to the CDN — your source plus the whole dist/ tree. | Packaging and publishing rules |
| Bundled asset | An image or font your widget imports; above the inline threshold the SDK emits it as a real file and resolves its URL from the bundle’s own location. (0.12.0+) | Keywords, assets and URLs |
category | content or layout on a widget summary. Anything but the literal layout resolves to content. | Manifest: widget summary |
| Composed page | The customer page a worker assembles from the renderer’s HTML and caches. Your widget is one island inside it. | How a widget renders |
| Confined relative path | A manifest path that cannot escape the published version prefix: no leading /, no scheme:, no \, no ... | Manifest: widget summary |
configSchema | The JSON Schema in your manifest (or sub-manifest) that drives the dashboard form. Emitted by zodToManifestSchema(). | Config schema and UI schema |
| Content widget | A widget that renders itself and hosts nothing — the default category. | Manifest: widget summary |
crossorigin trap | Adding crossorigin="anonymous" to a /p/ tag: the off-host 302 target sends no ACAO, so the bundle silently never executes. | Keywords, assets and URLs |
| CSR-only widget | A widget declaring "ssr": false — no SSR bundle, no ssr-entry.ts, mounted in the browser only. Give it an expectedHeight. | Manifest: widget summary |
data-hr-error | Host-element marker naming why a widget failed: mount-failed, render-failed, rate-limited, widget-fetch-failed, property-not-found. | Runtime, mount and the DOM contract |
data-hr-scheme | Host attribute meaning “follow the OS” — a pre-hydration CSS gate only, stamped by the server and removed the moment the runtime attaches. | Styling and theming |
data-hr-ssr-id | Server-written key into the page’s props registry, and the identifierPrefix used to hydrate. Layout shells never get one. | Runtime, mount and the DOM contract |
data-hr-theme | Host attribute carrying the resolved theme once JS owns theming. Your dark rules must target it, and the media-query arm must yield to it. | Styling and theming |
| Declarative Shadow DOM (DSD) | Server-emitted <template shadowrootmode="open">, so the browser attaches and styles your shadow root while parsing — no mount blink. | How a widget renders |
| Degraded page | A server-rendered page carrying any failure breadcrumb or failed prefetch. It still serves; its cache lifetime collapses. | Limits and error index |
dehydrateState | Optional SSR export: prefetch into the page’s shared React Query client so the browser hydrates without refetching. | Component and SSR module |
deprecated | Soft retirement of one suite widget: gone from the picker, existing placements keep rendering. Not a kill switch. | Manifest: widget summary |
| Dev panel | The bar npm run dev pins to the page — scenario, theme, latency and a settings textarea driving window.__HR_MOCK__. In a suite it takes a keyword list and pushes to all of them. | Dev sandbox and mocking |
| Dev sandbox | npm run dev (:3001): your widget — or every widget of a suite, with the layout composed — mounted against an MSW-mocked HomeRunner API. | Dev sandbox and mocking |
| dist-relative name | The normalised form every consumer reduces an asset reference to: everything after the last dist/, else the basename. | Keywords, assets and URLs |
| Elevated portal | A portal target with its own shadow root at document.body, for dialogs the widget’s own box would clip. Needs its tokens passed in. | Portals and dialogs |
| Embed snippet | The copyable HTML for a standalone placement: the runtime script, your bundle, and a host div carrying the keyword. | Runtime, mount and the DOM contract |
| Enforcement level | One of exactly four: publish ERROR, publish warning, silent runtime truncation, advisory (unvalidated). Every rule in the book carries one. | Limits and error index |
{env} prefix | prod, dev or local — the mandatory first segment of every published URL. An example URL without it is wrong and 404s. | Keywords, assets and URLs |
| Evergreen runtime | Since 0.10.0 React, React DOM, React Query and @homerunner-next/widget-core/runtime are externalized onto window.HRWidgetRuntime, so platform mount fixes reach your published bundle with no rebuild. | Runtime, mount and the DOM contract |
expectedHeight | Anti-CLS hint in CSS pixels on a widget summary. Emitted as data-hr-min-height for CSR-only widgets and baked into embed snippets. | Manifest: widget summary |
externalFetch | The host allow-list your server bundle may fetch beyond HomeRunner’s public API. Unvalidated at publish; enforced only in the sandbox. | Component and SSR module |
| Failure node | The hidden data-hr-widget-error breadcrumb the renderer substitutes for a widget that could not render. It degrades the page; it does not break it. | Component and SSR module |
| Feed | One customer site’s content scope. Plugins are installed per feed, and every widget row belongs to exactly one. | Install, customers and kill switches |
filter.property | The property the page (SSR) or the layout (CSR) pushes into every widget’s settings, so a slot child knows which listing it is on. | Composing a page |
| Fixtures | mocks/fixtures.ts — per-endpoint overrides for the dev sandbox’s generated data, keyed by endpoint. In a suite the widget factory is what gives each mounted widget its own keyword. | Dev sandbox and mocking |
getFinalSettings | The platform’s merge that produces the settings blob your component receives. Precedence chain and __parentColorScheme live with it. | Settings and options |
getInitialData | Optional SSR export whose return value becomes props.data and is replayed to the browser. Must be JSON-serialisable. | Component and SSR module |
getStaticAssets | Optional SSR export returning {css, js}. Prefer omitting it — everything it returns is re-resolved, and exporting it drops your declared fonts from <head>. | Component and SSR module |
| Hashed twin | The {base}-{sha8}{ext} copy the build writes beside every dist/ file, recorded in the build manifest and served immutably. | Keywords, assets and URLs |
hr-widget-build | The SDK’s build CLI: validates every summary, then runs the (widget × pass) matrix and finalises the manifests. Never run bare vite build on a suite. (0.11.0+) | SDK reference |
HRPlugins | window.HRPlugins[registryKey] = {component, category?} — the page-global registry your client bundle writes to. | Runtime, mount and the DOM contract |
HRWidgetRuntime | The page-level global the runtime IIFE installs: React, React DOM, React Query, widgetCore and the baked base URLs your bundle externalizes against. | Runtime, mount and the DOM contract |
| Hydration | Attaching React to server-rendered markup instead of re-creating it, using the props and query cache the server serialised. | How a widget renders |
| IIFE bundle | Your client bundle — dist/{slug}.iife.js (v1) or dist/{widget}/{widget}.iife.js (suite). | Keywords, assets and URLs |
| Install / Uninstall | The customer’s per-feed lifecycle. Install is Activate; Uninstall is refused while widgets built from your plugin still exist. | Install, customers and kill switches |
| Keyword | The single string that addresses a widget everywhere: plugin:{slug} (v1), plugin:{slug}:{widget} (suite), bare for a system widget. | Keywords, assets and URLs |
| Kill switch | One of three subtractive switches that withhold your code: platform suspension, platform per-widget, per-feed per-widget. Nothing is deleted from the CDN. | Install, customers and kill switches |
| Layout shell | The layout’s own markup around its slots. On a server-rendered page it is static light DOM with no shadow root and no mount — never interactive. | Layout widgets |
| Layout widget | A suite widget with category: "layout" that hosts other widgets in named slots. Needs an SSR bundle, a slots config field and a registered category. (0.11.0+) | Layout widgets |
LayoutWidgetProps | WidgetProps plus renderedSlots. Treat widgetType and target as optional — SSR supplies neither. | Layout widgets |
| Manifest | Root manifest.json — the registration document central caches and ships with every render. | Manifest: root fields |
| Manifest shape | Single-widget (v1) or suite (widgets[]). The discriminator is one line, and the choice is frozen at first publish. | The two manifest shapes |
| Manifest URL | Where your published manifest lives: {cdn}/{env}/{slug}/{version}/manifest.json. The {env} segment is never optional. | Keywords, assets and URLs |
| Marketplace | The Marketplace tab of a feed’s Plugins page — the only catalogue customers see. There is no global plugin browser. | Install, customers and kill switches |
| Media reference | A media/<file> path in the manifest (icon, cover, screenshots, readme). The rules differ per field, and media/ resolves only after a publish. | Manifest: root fields |
mediaSafeAuto | Opts a widget into parse-time auto scheme stamping. It is a promise about your CSS that nothing validates. (0.12.0+) | Manifest: widget summary |
mount(container, config) | The runtime entry your bootstrap calls. Selects [data-hr-widget="{keyword}"] inside the container, hydrates or client-renders each match. Returns void. | Runtime, mount and the DOM contract |
| Namespaced keyword | The suite form plugin:{pluginSlug}:{widgetSlug}, split at the first colon. | Keywords, assets and URLs |
options (raw) | The settings blob your component receives. It is never zod-parsed for plugins, on either side — call parseWidgetConfig yourself, everywhere. | Settings and options |
options-updated | The DOM event the dashboard preview dispatches to re-render a mounted widget with new settings. | Runtime, mount and the DOM contract |
| Page assignment | The per-feed mapping (Feed → Page URLs → Page layouts) of a server-rendered page to a layout. Absent means Automatic. | Layout widgets |
| Page layout | A layout currently assigned to one of a feed’s server-rendered pages, rendered with stored bindings only. | Layout widgets |
pages | The layout-only summary field declaring which pages the layout may be assigned to. (0.12.0+) | Layout widgets |
parseWidgetConfig | The SDK call that strips null leaves, coerces stringified scalars, lifts legacy spacing and applies your schema. The only real gate on stored settings. | Config schema and UI schema |
| Playground | The dashboard page for one widget instance: settings form, live preview, embed code and — for a layout — the Slot Configuration panel. | Config schema and UI schema |
| Plugin | One React component (or up to 24 of them) plus SSR modules and a manifest, submitted as a source zip and published by HomeRunner. You host nothing. | Anatomy of a plugin |
| Preflight | The checks you run yourself before zipping — including the reviewer-only gates you would otherwise fail blind. | Preflight and submit |
prefill | Per-slot list of system widget keywords the dashboard binds at creation time, so a new layout opens populated. Creation-time only. (0.12.1+) | Layout widgets |
| Preset | A root-level one-click composition: a layout, its children and their slot bindings, created atomically from the widget picker. Max 8. (0.11.0+) | Layout widgets |
| Props registry | window.HRWidget.__WIDGET_PROPS__, keyed by data-hr-ssr-id — the exact props the server rendered with, replayed at hydration. | Runtime, mount and the DOM contract |
| Public API | /public-api/v1 — the read-mostly HomeRunner API your widget fetches from, client-side and inside the sandbox. | Public API |
| Publish | The admin action that uploads the built zip under a new version prefix, verifies it, repoints the live manifest, then warms and purges. It also un-suspends. | Publishing, versions and rollback |
registerPlugin / registerPluginWidget | The two spellings of the same registry write. registerPluginWidget(p, w, C, meta) is registerPlugin("{p}:{w}", C, meta). (suite form 0.11.0+) | Runtime, mount and the DOM contract |
| Registry key | Everything after the plugin: prefix — {slug} or {slug}:{widget}. The key you register under and the key mount looks up. | Runtime, mount and the DOM contract |
renderedSlots | The pre-rendered children a layout receives per slot. SSR omits an empty slot’s key entirely; CSR emits []. Always write renderedSlots?.[name] ?? null. | Layout widgets |
resolvedTheme | The light/dark prop your component receives. On a server-rendered page an auto widget is handed light and never corrected — branch in CSS, not on this prop. | Styling and theming |
| Review | A human read of your source zip ending in approved, changes requested or rejected. Nothing notifies you — poll My plugins. | From your laptop to a customer page |
| Rollback | Repointing the live version at an earlier published prefix. It does not un-suspend and it cannot target a pre-0.10.0 build. | Publishing, versions and rollback |
runtime.widgetCore | The widget-core version your build stamps into the manifest. Generated output — never hand-write it. Publishing requires ≥ 0.10.0. | Manifest: root fields |
| Scaffold | npx create-hr-plugin <slug> — the non-interactive project generator. --template single (default) writes a v1 project, --template suite a three-widget suite with a layout. Both ship a dev sandbox and an SSR preview. | Install and versions |
| Scenario | One of the dev sandbox’s six data states — default, empty, single, large, loading, error. Config endpoints are never gated by it. | Dev sandbox and mocking |
settings.slots | Record<slotName, widgetId[]> stored on the layout instance — the customer’s bindings, in render order. Not part of the manifest. | Layout widgets |
| Shadow root | The isolated DOM tree each content widget renders into. Also where your stylesheet is linked, and why @font-face and Radix’s a11y probes behave oddly. | Runtime, mount and the DOM contract |
shadowDOM | Root-level manifest flag, whole-plugin, no per-widget override. It must agree with what your bootstraps pass to mount(). | Manifest: root fields |
| Shared query client | The single React Query client a rendered page owns. Prefetch into it from dehydrateState; the ["widget", …] and ["feed", …] key spaces are the platform’s. | Fetching data |
| Slot | A named region a layout declares in slots[] and renders from renderedSlots. | Layout widgets |
| Slot binding | One widget id stored under a slot name. Bindings pointing at deleted widgets are dropped at render; nothing prunes them. | Layout widgets |
| Slot editor | The Slot Configuration panel the dashboard injects into a layout’s own form, over your zod slots field. | Composing a page |
| Slug | Your plugin’s id, used verbatim as the CDN slug, the keyword stem and the /p/ path segment. | Manifest: root fields |
| Source zip | What you submit: manifest, package.json, src/, widgets/, media/ — never dist/, node_modules/ or .git/. | Packaging and publishing rules |
spacing | The base schema’s compound margin/padding/width/maxWidth field (0.9.0+). It replaced the old width: {maxWidth, unit} pair; apply it with resolveWidgetSpacingStyle. | Config schema and UI schema |
| SSR | Server-side rendering: the renderer evaluates your SSR bundle, runs the data hooks, and embeds the markup and dehydrated cache into the page. | How a widget renders |
| SSR bundle | The CommonJS file at dist/[{widget}/]{name}-ssr.umd.js. The umd in the name is historical. | Component and SSR module |
ssr-entry.ts | The re-export barrel the SSR pass compiles. It exists iff the widget’s summary declares ssr.url. | Component and SSR module |
| SSR preview | npm run dev:ssr (:3003) — a local harness for the server path, one widget at a time. A suite names it: --widget {slug} (0.12.2+). It is not the renderer’s envelope; know the divergences before trusting it. | Previewing SSR locally |
| Sub-manifest | widgets/{slug}.manifest.json — one suite widget’s configSchema + uiSchema, generated by your own inject-schema script, fetched by the dashboard only. (0.11.0+) | Config schema and UI schema |
| Submission | Your source zip on Dashboard ▸ Plugins ▸ My plugins, and the five-state timeline it moves through. Re-submitting replaces whatever is in flight. | From your laptop to a customer page |
| Suite | The modern manifest shape: up to 24 widgets under one version, one review, one publish. New plugins should start here, even with one widget. (0.11.0+) | The two manifest shapes |
| Suspension | status = suspended — the platform-wide kill switch. /p/ 404s every file and every instance becomes a failure node. | Install, customers and kill switches |
| Symbolic component token | The uiSchema component name the dashboard resolves to a real form control. The canonical list — and what each must be paired with — is one table. | Config schema and UI schema |
| System widget | A first-party HomeRunner widget, addressed by a bare keyword (gallery, reviews) with no plugin: prefix; its assets are served from /w/, not /p/. | Keywords, assets and URLs |
uiSchema | The symbolic UI declaration beside your configSchema. It covers your own fields only; a top-level entry replaces the platform’s control wholesale. | Config schema and UI schema |
usePortalContainer | Hook returning the portal node inside your shadow root — the default target for dialogs and tooltips. | Portals and dialogs |
useShadowHost | Hook returning your widget’s host element (the [data-hr-widget] div). | Portals and dialogs |
useTopLevelPortal | Hook returning a portal target outside every shadow root, for dialogs the widget’s own box would clip. Pass it your token CSS. | Portals and dialogs |
| Version prefix | {env}/{slug}/{version}/ — the immutable key prefix every published object lives under. Bumping the version changes the prefix, not the /p/ URL. | Keywords, assets and URLs |
| Visibility | public (every account) or private (granted accounts only). Chosen by the reviewer; you cannot set or read it. | Install, customers and kill switches |
viteHomerunnerWidget | The Vite preset from @homerunner-next/widget-core/vite that supplies plugins, define, build and server. Drop it into vite.config.ts. | SDK reference |
| vm sandbox | The node:vm context the renderer evaluates your SSR bundle in: seven shared modules, stubbed browser globals, bounded execution. Not a security boundary. | Component and SSR module |
/w/ | The system-widget asset path (including runtime.iife.js). Plugin assets never live here; the scaffold’s local server only mirrors the shape. | Keywords, assets and URLs |
| Widget | One renderable unit on a page. Plugin widgets and system widgets share the same runtime, DOM and settings contracts. | Anatomy of a plugin |
| Widget icon | Optional per-widget icon (media/<file> or an absolute URL) shown on picker cards and the plugin page; falls back to the root icon, then a glyph. (0.12.0+) | Manifest: widget summary |
| Widget slug | A widget’s id, unique inside its plugin, ^[a-z0-9][a-z0-9-]*$, never dist / widgets / media. It names the dist/ directory and the keyword tail. | Manifest: widget summary |
| Widget summary | One object in widgets[] — the whole per-widget contract the renderer ever sees. (0.11.0+) | Manifest: widget summary |
WidgetProps | The props every widget component receives. Import it from /contracts rather than hand-rolling it; what each path actually supplies differs. | Component and SSR module |
widgetSchema | The nine-field base zod schema every widget extends (spacing, colorScheme, filter, lightModeColors, darkModeColors, font, language, section, customCss). The platform renders none of them for you. | Config schema and UI schema |
widgetType | A required, non-empty single-widget root field whose value is read by nothing. Routing uses the plugin id. | Manifest: root fields |
Numbers, caps and verbatim error strings are not repeated here — they live in Limits and error index, and symptoms are indexed in Troubleshooting.