docs
/
Studio Manager

Page JavaScript

The style slots on a page record, what executes and what does not, and the constraints that apply to code running inside a rendered page.

A page record carries a top-level style object — a sibling of data, not a key inside it — holding the assets injected into the document head when the page renders.

SlotInjected as
style.javascriptAn inline <script>
style.cssAn inline <style>
style.scriptLinks<script src> elements
style.styleLinks<link rel="stylesheet"> elements

This is where page behaviour belongs.

req("POST", f"/repository/update-partial/page/{sk}", {
    "sk": sk,
    "version": rec["version"],
    "style": {"javascript": js, "css": css},
}, token=t)

{"style": {}} clears the slots.

data.style is read by nothing. A payload written there is stored, returns 201, and never executes — no error, no warning. Confirm placement by reading the record back:

print("style" in rec)                   # True  — correct
print("style" in rec.get("data", {}))   # False — the wrong place

There is no practical size limit. A production product customizer runs on 113,115 characters in this slot.

What executes, and what does not

WhereExecutes
style.javascriptYes
style.scriptLinksYes
<script> with a body, in data.htmlNo — the parser discards script bodies
<script> in the page's <head>No — head HTML is injected via innerHTML, which never runs scripts
data.style.javascriptNo — nothing reads it
onclick, onload and other handler attributesYes — attributes survive parsing

The cause of the third row is the parser configuration used to turn page HTML into the virtual DOM:

blockTextElements: { script: false, noscript: false, style: false, pre: true }

blockTextElements lists elements whose raw text is retained. script: false discards the body; the element remains as an empty node. See Pages and rendering.

It runs before the page exists

style.javascript is injected into the head, so it executes before the body is parsed and before window.appmint mounts. Every element lookup at the top level returns null.

Gate on what you need:

(function boot() {
  if (!document.getElementById('app-root') || !(window.appmint && window.appmint.cart)) {
    return void setTimeout(boot, 30);
  }
  // …
})();

Check a real element from your own markup and the specific namespace you use — namespaces mount progressively, so window.appmint alone is not a sufficient test.

Do not substitute DOMContentLoaded. It may have fired before your script was injected, in which case the listener never runs — an intermittent, silent failure.

Constraints on code in this slot

Globals are not shared with attribute handlers. A function assigned to window from style.javascript is not reliably visible to an inline onclick on a hydrating page. Bind with addEventListener instead of defining globals for markup to call.

Bindings cannot call JS globals. data-bind expressions have Number, Math, parseInt and toLocaleString shadowed to undefined, and the binding renders blank rather than erroring. Use data-format, or compute in code and bind the result.

Make it idempotent. A page can render more than once. Mark what you bind to:

var root = document.getElementById('app-root');
if (root.dataset.bound) return;
root.dataset.bound = '1';

Use textContent for record values. Anything a person typed or a record supplied is untrusted; interpolating it into innerHTML is an injection site.

Debugging

Put a flag above the gate while developing:

window.__APP_LOADED = true;
(function boot() { /* … */ })();

Then, on the rendered page:

ReadingMeans
__APP_LOADED undefinedThe slot is wrong or empty — the code was never delivered
__APP_LOADED true, nothing happensDelivered; your gate never opened
Elements found but no behaviourBound to nodes that were later replaced by a redraw

That first distinction — not delivered versus delivered and waiting — separates two completely different problems, and guessing between them is where the time goes.

The Scripts library

When the same code belongs on several pages, keep it in DAM › Scripts (admins only) rather than pasting it into each page's style.javascript.

A script has a name (lowercase letters, numbers, hyphens and underscores, fixed after the first save), a description and a status — Draft, Active or Disabled. Write the code in the editor or upload a .js file. Scripts are plain JavaScript on the window.appmint API, and the editor has a reference panel beside the code: click a method to insert it at the cursor, or look up the declarative HTML attributes that need no JavaScript at all.

Saving hosts the code as a file in your organization's storage — <org>/client-apps/<name>/<name>.js — and records its URL as the script's entry point; Open entry point in the list opens it. To load a script on a page, add that URL to the page's style.scriptLinks. It is injected into the document head like the inline slot, so it needs the same readiness gate.