# Section Scripting

> How section JavaScript runs on Lexsis pages and cart modules, what it receives, and the limits the runtime enforces.

Canonical URL: https://77865786950d:3005/scripting

A section's plain `<script>` adds behaviour to that one section: toggles,
counters, form logic, small API calls. The renderer runs it after the page
hydrates, hands it a `lifecycle` object, and cleans everything up when the
section is removed or misbehaves.

Use the lightest tool first. CSS and `data-behavior` primitives cover most
motion; [managed motion](/pages/animations) covers custom animation; islands
cover stateful commerce UI. Section JS is for the behaviour that is left.

## Where scripts run

| Context | Arguments | Notes |
|---|---|---|
| Page section `<script>` | `section, lifecycle, motion, MutationObserver, setTimeout, setInterval, requestAnimationFrame` | Published pages and previews |
| Custom cart module | `root, section, lifecycle, motion, MutationObserver, setTimeout, setInterval, requestAnimationFrame` | See [Cart API](/scripting/cart) |
| Managed motion `<script type="application/lexsis-motion">` | A motion context (`dom`, `scheduler`, …), not `lifecycle` | See [Animations](/pages/animations) |

Section scripts do not run on experiment pages served by the edge worker
(`window.__LX_DISABLE_SECTION_SCRIPTS__` is set), so write behaviour that
leaves the section readable without it. Cart modules still mount there.

## Script arguments

- **`section`**: on a page, the authored inner `<section>` element. In a cart
  module it is a deprecated alias of `root`.
- **`root`** (cart modules only): the `[data-cart-custom-module]` wrapper.
- **`lifecycle`**: the runtime API documented in this section.
- **`motion`**: the same object as `lifecycle`, kept for older scripts.
- **`MutationObserver`, `setTimeout`, `setInterval`, `requestAnimationFrame`**:
  managed replacements that behave like `lifecycle.observeMutations`,
  `lifecycle.timeout`, `lifecycle.interval` and `lifecycle.frame`. Prefer the
  `lifecycle.*` names: the compiler rejects `new MutationObserver(`, and
  rejects bare `setInterval(` / `requestAnimationFrame(` in scripts that never
  reference `lifecycle.`.

On pages, `lifecycle.root` is the section wrapper (`[data-section-id]`), which
contains `section`.

A script may `return` a function. It runs as a cleanup, the same as
`lifecycle.addCleanup(fn)`.

```html
<!-- section: shipping-note -->
<section>
  <button type="button" data-toggle>Shipping details</button>
  <p data-panel hidden>Free shipping over ₹999.</p>
</section>
<script>
const button = lifecycle.query("[data-toggle]");
const panel = lifecycle.query("[data-panel]");
lifecycle.on(button, "click", () => {
  panel.hidden = !panel.hidden;
});
</script>
```

## Runtime API

| Area | Members | Page |
|---|---|---|
| DOM and events | `root`, `query`, `queryAll`, `on`, `guard` | [DOM and events](/scripting/dom-and-events) |
| Timers, observers, cleanup | `timeout`, `interval`, `frame`, `loop`, `observeVisibility`, `observeMutations`, `addCleanup`, `cleanup`, `stopped` | [Timers and observers](/scripting/timers-and-observers) |
| Storage | `storage.session`, `storage.local`, `storage.onChange` | [Storage](/scripting/storage) |
| Network | `fetch`, `lx:connection/…` | [Network](/scripting/network) |
| Forms | `forms.schema`, `forms.submit` | [Forms](/scripting/forms) |
| Cart | `cart`, `onCart`, `setVisible` | [Cart](/scripting/cart) |

Every member is available in page sections, previews and cart modules.

## Safety model

Section JS shares the page realm, so the runtime is a guardrail, not a sandbox:

- **Before running**, the script is checked against the section script policy.
  If a capability is blocked, the script is skipped and the section's content
  is made visible. See [Validation and errors](/scripting/validation).
- **While running**, callbacks are timed and the section is watched. A section
  that trips the [watchdog](/scripting/timers-and-observers#watchdog) is
  stopped and its content revealed.
- **When removed**, every listener, timer, observer, pending fetch and
  registered cleanup is released.
