Skip to main content
Theme scripts and plugins — never renderers — can talk to the runtime directly.
Prefer the data attributes over dispatch. Quantity, variant, selection, and add-to-cart all have a supported path already: put the right data-nameless-* attribute on the right element and let the runtime drive it. That path is the contract we test and keep stable.Inside a renderer, dispatch is forbidden outright — no exceptions. In other scripts, treat it as a last resort for cases the attributes genuinely can’t express (e.g. a bundle driven from an unrelated part of the page). Reading state with subscribe carries none of these caveats.
Every row above has an attribute equivalent — see Data attributes. Reach for the attribute first. "bundles" is the only subscribe topic. Before the runtime installs, dispatch returns { ok: false, code: "NOT_READY" }. Failure codes you may see: NOT_READY, UNKNOWN_ACTION, INVALID_PAYLOAD, INVALID_QUANTITY, UNKNOWN_BUNDLE, UNKNOWN_SELECTOR, UNKNOWN_VARIANT, WRONG_SELECTOR_KIND, EMPTY_SELECTION, VARIANT_UNAVAILABLE, SOLD_OUT, CART_HTTP_ERROR, CART_REJECTED, PLUGIN_BLOCKED, HANDLER_THREW. Anything on window.nameless prefixed with __ is an internal detail — don’t build against it.

Debugging

Pre-ship checklist

Renderer

  • defineRenderer called once, at top level, unguarded
  • Repaints entirely from snapshot on every call; no cached nodes, no accumulated state
  • No listeners, no dispatch, no fetch, no globals
  • Branches on all three sel.kind values, including collectionSingle with no resolved product
  • Variant <option value> is the variant id; qty controls show entry.quantity
  • collectionMulti controls carry both the selector id and data-nameless-product-id
  • Tier buttons use hidden inputs, not an attribute on the button
  • ATC button rendered only when meta.atcOverride is false
  • Every snapshot string escaped; every merchant-visible string through ctx.t (and not escaped)

Styling

  • Every rule scoped under [data-nameless-widget]
  • No global element selectors, no theme classes, no external imports
  • Class vocabulary matches the renderer exactly
  • Markup still readable and operable with the CSS disabled

Plugins

  • before hooks return within 1500ms, or tolerate being cut off
  • Blocks use a meaningful code and a shopper-readable message
  • lineProperties keyed by selector id; __FB_ATC_UID left untouched
  • Resolvers call next() and adjust, rather than replacing a stage wholesale
  • No dispatch calls that a data-nameless-* attribute could have handled
  • Hook failures verified to leave the shopper’s add-to-cart working