# clayjs > clayjs makes an HTML file malleable: the page you are looking at can be edited like a > document and saved, whole, back into its own file. One script tag, no build step, no > account. The document is the app AND the database: state lives in the DOM, and a save > is one POST of the entire serialized document to the host that holds the file. This file is the complete reference for agents, condensed from https://clayjs.com/docs, https://clayjs.com/advanced, and https://clayjs.com/plugins. Human-readable versions live at those URLs. clayjs is MIT-0 licensed. npm builds for bundlers: @panphora/clayjs. ## The one-paragraph integration To make a static HTML file malleable: add `` as the last element inside ``. Add an `autosave` attribute to the `` element. Add an `editable` attribute to each element a person should edit as rich text (headings, paragraphs, note containers). Add a `persist` attribute to any form control whose value should survive saving. Mark page UI that should never be written to disk with `clay="no-save no-watch"`. Do not write any save logic or add a save button: clayjs saves the whole document automatically, and the host writes it to disk. ## Hosts (who writes the file) clayjs is client-side; a host accepts the save and writes bytes: - HTML Clay, a small desktop app (https://htmlclay.com): serves local `.htmlclay` files at http://127.0.0.1, writes saves back to disk, keeps automatic version history. - hyperclay.com: hosts the same files online. - Your own server: implement one route (see "The endpoint spec" below, ~20 lines). ## Loading ```html ``` The default build includes the save lifecycle and rich text (`editable`). Plugins load conditionally through the URL, in the browser only: - `?plugins=` comma-separated plugins to add, e.g. `clay.js?plugins=sync,undo` - `?exclude=` remove a default-on plugin, e.g. `clay.js?exclude=richclay` Loadable plugins: `richclay` (default on), `indicator`, `sync`, `sortable`, `undo`, `cms`, `quickcrop`, `upload`, `wire`, `demo`. Everything else is a separate library ("satellite") with its own script tag: clay-ui, clay-events, clay-options, clay-dom, all.js, clay-utils, clay-internals, clay-data, sap.js. To call a satellite from an inline script right after its tag, wait for it: `await clay.loaded.ui` (or `.dom`, `.all`, `.utils`, `.events`, `.options`, `.data`, `.sap`, `.internals`). Offline: `https://clayjs.com/v1/clay.standalone.js` is the whole library in one readable file (core, every plugin, every satellite), built from the same source. Download it, keep it beside the HTML file, and load it with the same query params: ``. `plugins=` then decides what runs, not what downloads, and every `clay.loaded.*` promise exists without a satellite tag. Delete any satellite tags the page had: the file carries them all, and a second `sap.js` mounts a second runtime. `clay.Sap` and `clay.extractData`, which a tag defines synchronously, arrive one microtask later here; `await clay.loaded.sap` (or `.data`) covers both. `/1.1.0/clay.standalone.js` is that exact release, pinned, and every later release has the same form; the npm tarball carries it at `dist/clay.standalone.js`; the file's first line names its version. Two things still reach the network, both opt-in: the CMS sidebar's font comes from jsDelivr and falls back to the system monospace, and autosave debugging (`localStorage` key `clay:debug:autosave`) imports its diff library from esm.sh. Saving still needs a host that writes the file; HTML Clay does that on the machine itself, with no network. ## Core API: window.clay - `clay.ready` — Promise that resolves once clayjs has booted (core loaded, plugins attached). In inline scripts, `await clay.ready` before touching anything else. `clay:ready` fires on `document` at the same moment. - `clay.save()` — snapshot the page and save it. Skips when nothing changed. Returns `Promise<{ok, msg, msgType, code, etag}>`; check `ok`. `msgType` is `success`, `error`, `skipped` (nothing was sent), or `unknown` (the request timed out, so the write may or may not have landed). A host may answer with its own severity, such as `warning`. Never rejects. - `clay.save.force()` — save even when nothing appears to have changed. - `clay.getHTML()` — the exact HTML string a save would send, after all cleanup. - `clay.addDocumentTransform(fn)` — register a callback that receives the cloned document before serialization. The live page is never touched. Runs on every change check too, so keep it pure and repeatable (no timestamps, counters, or network). - `clay.onSnapshot(fn)` — like `addDocumentTransform`, but runs for every snapshot, including live-sync broadcasts. - `clay.isEditMode` — whether this session may edit. - `clay.isOwner` — whether the platform's owner cookie is set (URL and global overrides don't affect it, unlike `isEditMode`). - `clay.toggleEditMode()` — flip between edit and view mode (reloads the page). - `clay.cacheBust(el)` — re-download one resource by stamping `?v=` onto its `href` or `src`. - `clay.Mutation` — the shared mutation hub (one MutationObserver for the whole page, region rules applied). `clay.Mutation.onAnyChange(opts, cb)` respects `clay="no-watch"` regions. - `clay.morph(oldEl, newEl)` — content-based DOM morphing engine: morphs `oldEl` in place to match `newEl`, preserving focus, inputs, and animations (sync plugin). - `clay.undo` — document-wide undo singleton: `clay.undo.undo()` / `clay.undo.redo()` (undo plugin). - `clay.cms` — the content panel: `clay.cms.open()` (cms plugin). - `clay.RichClay` — the rich-text editor class behind `editable` (richclay plugin). - `clay.quickcrop(file, opts)` — crop modal: resolves `{blob, dataURL, width, height}`, or `null` if cancelled (quickcrop plugin). - `clay.upload` — pick a file and get it into the page (upload plugin). - `clay.wire` — per-file control channel to a process on the user's machine: `send`, `cancel`, `get`, `list`, `isBusy`, `on` (wire plugin). - `clay.region` — region policy helpers and strip selectors (see clay.internals.region; the same object, also published as `STRIP_FROM_SAVE`-style constants). In view mode the edit-only members are absent: `window.clay` holds just `ready`, `toggleEditMode`, `isEditMode`, `isOwner`, `Mutation`, and `region` (plus `morph`/`cms` when those plugins load). Feature-detect with `'save' in clay`. Stability contract (since 1.0.0): `clay.*` from clay.js and `clay.*` from a satellite are stable; no name changes without a major version. Anything else under `src/` is reachable by direct import but may change in any release. ## The HTML surface (attributes) - `editable` (any element except a custom element) — rich text editing with a floating toolbar (richclay, default on). Tokens combine: `editable="single-line no-toolbar toolbar-on-select"`. A hyphenated tag is skipped, because `editable` is a common boolean property on a component and means something else there; such an element opts in with `clay-editable` instead. Native `contenteditable` also works for plain text. - `persist` (form controls) — writes the control's current value into the HTML so it survives the save. `password`, `hidden`, and `file` inputs are always skipped, so a secret cannot be written into the file by adding one attribute. - `trigger-save` (buttons) — clicking calls `clay.save()`. Put it on a `