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.
| Slot | Injected as |
|---|---|
style.javascript | An inline <script> |
style.css | An 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 placeThere is no practical size limit. A production product customizer runs on 113,115 characters in this slot.
What executes, and what does not
| Where | Executes |
|---|---|
style.javascript | Yes |
style.scriptLinks | Yes |
<script> with a body, in data.html | No — the parser discards script bodies |
<script> in the page's <head> | No — head HTML is injected via innerHTML, which never runs scripts |
data.style.javascript | No — nothing reads it |
onclick, onload and other handler attributes | Yes — 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:
| Reading | Means |
|---|---|
__APP_LOADED undefined | The slot is wrong or empty — the code was never delivered |
__APP_LOADED true, nothing happens | Delivered; your gate never opened |
| Elements found but no behaviour | Bound 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.
Related
- Where your code goes — the same ground, with the application patterns
- Pages and rendering — the storage shapes and the parser
- Runtime attributes — the declarative alternative
- Actions reference — what
window.appmintexposes