Dropping into the primitives layer
This recipe shows how to use the low-level PLDocument and PLElement classes from pagelove/primitives.mjs to read and write individual elements programmatically, outside the declarative binding flow.
When to reach for primitives
Most applications use the Pagelove class and declarative bindings. The primitives layer is useful in a few specific situations:
- Tooling scripts that run in a build step or CI pipeline and need to read or write elements without rendering a page.
- Non-browser integrations where the full declarative runtime is not needed — a Node.js script, a service worker, or a command-line tool.
- Programmatic reads where you need precise control over the HTTP request — choosing a specific selector, inspecting the raw response, or working with ETags directly.
If your use case involves a rendered page with live data, start with the Pagelove class instead. The primitives layer is what the high-level API uses internally.
Import the module
<script type="module">
import { PLDocument, PLElement } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
</script>
The module exports two classes: PLDocument (a document-level wrapper) and PLElement (an element-level wrapper that knows how to issue scoped HTTP requests).
Discover capabilities with OPTIONS
Before issuing requests, call OPTIONS() on a PLDocument to discover which elements the server allows you to interact with and which methods are permitted:
<script type="module">
import { PLDocument } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
const doc = new PLDocument('/notes.html');
await doc.OPTIONS();
</script>
OPTIONS() issues an OPTIONS request with Accept: multipart/mixed. The server responds with a multipart body describing the selectors and allowed methods for each element. After OPTIONS() resolves, matching DOM elements have their allowed methods attached directly — element.GET(), element.PUT(), element.DELETE() — ready to call.
Read a specific element
To read a single element without capability discovery, construct a PLElement directly and call GET():
<script type="module">
import { PLDocument, PLElement } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
const doc = new PLDocument('/notes.html');
const el = new PLElement(doc.url, document.getElementById('note-42'));
const node = await el.GET();
console.log(node.textContent);
</script>
GET() issues a fetch with Range: selector=#note-42 (derived from the element's id), parses the response body as an HTML fragment, and returns the resulting DOM node. The selector is generated automatically from the element — preferring id, falling back through itemprop, class names, and positional selectors.
Write an element back
After modifying a node, call PUT() to send it back to the server:
<script type="module">
import { PLDocument, PLElement } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
const doc = new PLDocument('/notes.html');
const target = document.getElementById('note-42');
const el = new PLElement(doc.url, target);
target.querySelector('[itemprop="title"]').textContent = 'Updated title';
await el.PUT();
</script>
PUT() serializes the wrapped element's outerHTML and sends it as the request body. The Range header scopes the write to the element's selector. If the element has an ETag (populated by a previous GET or OPTIONS), If-Match is included for conditional update.
A complete example: logging an element's text
This script reads a specific heading from a document and logs its content:
<script type="module">
import { PLDocument } from 'https://pagelove.github.io/beta-js/pagelove/primitives.mjs';
const doc = new PLDocument('/about.html');
await doc.OPTIONS();
const heading = document.querySelector('h1');
if (heading && typeof heading.GET === 'function') {
const fresh = await heading.GET();
console.log('Heading text:', fresh.textContent);
}
</script>
After OPTIONS() runs, the h1 element has GET attached if the server allows it. The script calls GET() to fetch the latest version and logs the text content.
See also
- Primitives — the full reference for
PLDocument,PLElement, ETag handling, and request format. - The Pagelove class — the high-level API built on top of primitives.