*load
Summary
*load.file loads JSON data from a user-selected file and merges it into the Sercrod host’s data. *load.session loads JSON from browser sessionStorage and applies the same merge rules. *load.store loads JSON from persistent browser storage backed by IndexedDB and applies the same merge rules. If a staged view is active (via *stage), the JSON is merged into the stage; otherwise it is merged into the live data. *load remains as the legacy-compatible file form, equivalent to *load.file when no storage suffix is used.
Typical use:
- Put
*load.fileon a button or other clickable element. - Use
*load.session="'key'"when the source is asessionStoragekey. - Use
*load.store="'key'"when the source is persistent browser storage. - Optionally use
*keysto choose top-level properties from the JSON. - Optionally use
*responseto place the loaded value under one host data key. - Sercrod reads JSON from the selected source, parses it, merges it into data or stage, and triggers a re-render.
Basic example
A simple load button that merges the entire JSON into host data:
<serc-rod id="profile" data='{"user":{"name":"","email":""}}'>
<p>Name: <span *print="user.name"></span></p>
<p>Email: <span *print="user.email"></span></p>
<button type="button" *load.file>Load profile…</button>
</serc-rod>
If the user selects a JSON file like:
{
"user": {
"name": "Alice",
"email": "alice@example.com"
}
}
then after loading:
user.namebecomes"Alice".user.emailbecomes"alice@example.com".- The view is refreshed automatically.
Load selected keys into one destination:
<button type="button" *load.file *keys="profile settings" *response="'draft'">
Load draft
</button>
In this form:
*load.filedescribes the browser file source.*keysselects keys from the loaded JSON.*responsestores the selected value underdraft.
Load selected keys from the current browser session:
<button type="button" *load.session="'profile-draft'" *keys="profile" *response="'draft'">
Load session draft
</button>
In this form:
*load.sessiondescribes thesessionStoragekey.*keysselects keys from the stored JSON.*responsestores the selected value underdraft.
Load selected keys from persistent browser storage:
<button type="button" *load.store="'profile-draft'" *keys="profile" *response="'draft'">
Load persistent draft
</button>
In this form:
*load.storedescribes the persistent browser storage key.- Sercrod reads JSON from IndexedDB.
*keysand*responseuse the same selection and placement rules as file and session loads.
Behavior
-
*load.fileis an action directive that attaches file-loading behavior to an element. -
*load.sessionis an action directive that reads JSON fromwindow.sessionStorageon click. -
*load.storeis an action directive that reads JSON from IndexedDB on click. -
The directive works with the browser’s file picker and uses
FileReaderto read the chosen file. -
Only JSON is expected; other file types are not supported by the current implementation.
-
The directive merges the parsed JSON into:
_stage, if the host has a staged view (for example due to*stage)._data, otherwise.
-
The merge strategy depends on
*keysand*response:- No
*keys, no*response: merge the entire JSON object into the target object withObject.assign. *keys, no*response: copy only those top-level properties into the target object.*response: place the loaded value through the standard response target.
- No
-
After a successful load, Sercrod dispatches a
sercrod-loadedevent and callsupdate()on the host to re-render the view.
Aliases and compatibility:
*load.fileandn-load.fileare aliases.*load.sessionandn-load.sessionare aliases.*load.storeandn-load.storeare aliases.*loadandn-loadremain supported as the old file-load spelling.- In new examples, prefer explicit action forms plus
*keysand*responsewhere needed.*intoremains a compatibility alias for a simple destination key.
Storage and merge semantics
Key and destination values:
-
If
*keysand*responseare omitted:-
The parsed JSON must be an object.
-
Sercrod merges all enumerable properties into
_stageor_data:- With stage:
Object.assign(this._stage, json) - Without stage:
Object.assign(this._data, json)
- With stage:
-
-
If
*keyshas a value:-
The value is split by whitespace into a list of property names:
-
*keys="user settings"becomes
["user","settings"].
-
-
For each property name
p:- With stage:
this._stage[p] = json[p] - Without stage:
this._data[p] = json[p]
- With stage:
-
Only direct top-level keys are supported; dotted paths or nested selectors are not interpreted.
-
-
If
*responsehas a simple destination value:- Without
*keys, the entire loaded JSON is assigned to the response destination. - With one key,
json[key]is assigned to the response destination. - With multiple keys, an object containing those keys is assigned to the response destination.
- Without
Old spelling:
<button *load="user settings">Load user+settings</button>
This remains supported for compatibility. Treat the value as old *keys syntax.
Error handling:
-
The chosen file is read as text and parsed with
JSON.parse. -
*load.sessionwarns and makes no data change when the storage key is empty, inaccessible, missing, or contains invalid JSON. -
*load.storewarns and makes no data change when IndexedDB is unavailable, the key is missing, or the stored JSON cannot be parsed. -
If parsing fails and Sercrod is configured to warn, the runtime logs:
[Sercrod warn] *load JSON parse: ...
-
On parse error, no merge is performed and the view is not updated.
File input integration
*load.file and legacy *load work both with native file inputs and with regular clickable elements.
-
If the element is an
<input type="file">:- Sercrod reuses the native file input.
- If the input has no
acceptattribute, Sercrod sets it to"application/json"by default. - On
change, the first selected file is read and processed.
-
If the element is not an
<input type="file">:- Sercrod attaches a
clickhandler to the element. - When clicked, Sercrod creates a hidden
<input type="file">, sets itsacceptattribute, and forwards the selection to*load. - The temporary file input is not meant to be visible or controlled directly.
- Sercrod attaches a
Accept attribute:
- If the element has an
acceptattribute, Sercrod respects it. - If not, Sercrod uses
"application/json"as the default. - This influences what the browser shows in the file picker but does not perform additional runtime validation beyond JSON parsing.
Stage interaction
*load is designed to cooperate with staged editing:
- If the host has an active stage (for example due to
*stage),*loadmerges into_stageinstead of_data. - This lets you preview or edit the loaded data in a staged view and then decide when to apply it.
Typical pattern:
<serc-rod id="editor" data='{"doc":{"title":"","body":""}}'>
<section *stage>
<label>
Title:
<input *input="doc.title">
</label>
<label>
Body:
<textarea *input="doc.body"></textarea>
</label>
<button type="button" *load.file *keys="doc">Load draft…</button>
<button type="button" *apply>Apply</button>
<button type="button" *restore>Restore</button>
</section>
</serc-rod>
In this pattern:
*load.file *keys="doc"replaces the stageddocobject withjson.docfrom the file.*applycopies staged changes back into the live data.*restorediscards staged changes and returns to the last stable state.
Evaluation timing
-
*loadis evaluated when Sercrod renders the element that carries it. -
During rendering:
- Sercrod clones the original element.
- It attaches the necessary event listeners for the selected load source.
- It appends the cloned element to the DOM and returns from the internal render function.
-
*loaddoes not perform any data changes during rendering itself.- Data changes happen later, in response to user interaction.
- File loads react to file selection.
- Session and store loads react to click and then read from browser storage.
-
When JSON is successfully loaded and merged, Sercrod explicitly calls
update()on the host to re-run the render pipeline and update the view.
Execution model
Conceptually, the runtime behaves like this for *load:
-
Sercrod detects a load directive on an element.
-
It clones the element.
- All attributes and children are copied as-is.
- The
*load/n-loadattribute is preserved on the clone for visibility, but Sercrod does not re-interpret it later.
-
It resolves the action attribute:
*load.filemeans browser file input.*load.sessiongives asessionStoragekey.*load.storegives a persistent browser storage key.- legacy
*loadvalues are treated as old*keyssyntax.
-
It parses
*keysand*response(*intois accepted as an alias). -
For file loads, it determines the desired
accepttype:- Uses the element’s own
acceptattribute if present. - Otherwise, defaults to
"application/json".
- Uses the element’s own
-
It wires source handling:
-
For
*load.store, it attaches a click listener that reads the JSON string from IndexedDB. -
For
*load.session, it attaches a click listener that reads the JSON string fromsessionStorage. -
For file loads, if the cloned element is an
<input type="file">:- Ensures
acceptis set. - Adds a
changelistener that callshandleFile(file)for the selected file.
- Ensures
-
For file loads on any other element (button, link, etc.):
- Adds a
clicklistener. - That listener creates a temporary
<input type="file">, setsaccept, and listens forchange. - When a file is chosen, it calls
handleFile(file).
- Adds a
-
-
The common JSON path:
- Reads JSON text from the selected source.
- Parses the JSON.
- Merges or places it into
_stageor_dataaccording to*keysand*response. - Dispatches
sercrod-loadedwith source details. - Calls
update().
-
The cloned element is appended to the parent in the rendered DOM; the original template node is not appended.
Variable creation
*load does not create new template variables:
- It does not add loop variables, local aliases, or special names to the scope.
- All changes happen directly in the host’s
_data(or_stage) object. - Templates and expressions continue to use the regular data paths (
user,settings, etc.) after the data is updated.
Scope layering
*load respects the existing scope model:
- It operates on the Sercrod host’s data or stage, not on local loop scopes.
- It does not change how
$data,$root, or$parentare injected. - After a successful load, any expressions that read from the updated data see the new values at the next render.
Because *load is an action on the host data, it does not affect how inner scopes are layered; it only changes the values they eventually read.
Parent access
*load does not introduce a new parent object:
- Parent access via
$parentand$rootremains unchanged. - Any templates that use
$parentor$rootsimply see updated data after the load and re-render, as long as they reference the affected fields.
Use with conditionals and loops
You can place *load inside conditional blocks or loops just like any other action element:
-
Inside
*if:- The element exists and is interactive only when the
*ifcondition is truthy.
<div *if="canLoad"> <button type="button" *load.file>Load config…</button> </div> - The element exists and is interactive only when the
-
Inside loops:
- Each iteration can have its own
*loadelement, although typically you want just one loader per host.
<serc-rod data='{"sections":[{"id":1},{"id":2}]}'> <section *each="section of sections"> <h2 *print="section.id"></h2> <button type="button" *load.file *keys="section">Load section…</button> </section> </serc-rod> - Each iteration can have its own
Restrictions:
-
*loadis not a structural directive and does not control how many times an element is rendered. -
It is best used for standalone controls (buttons, links, inputs) rather than for elements that also carry structural directives like
*foror*each. -
Combining
*loadwith other action directives that also replace the element (such as*save,*post, or*fetch) on the same element is not recommended:- Only one branch in the internal evaluation order will run.
- Other directives on the same element will effectively be ignored.
- Use separate elements if you need multiple actions.
Best practices
-
Use dedicated controls:
- Attach
*loadto buttons or file inputs specifically intended for loading data. - Avoid mixing
*loadwith other unrelated behaviors on the same element.
- Attach
-
Keep the JSON shape predictable:
- Decide on a stable JSON schema for exports and imports (for example, via
*save). - Document which top-level properties exist (
user,settings, etc.).
- Decide on a stable JSON schema for exports and imports (for example, via
-
Use
*keysfor partial updates:-
When you want to protect unrelated data from being overwritten, specify only the properties you want to import:
*load.file *keys="user settings"
-
-
Combine with staged editing:
- Pair
*loadwith*stage,*apply, and*restoreto allow safe previewing of loaded data before committing.
- Pair
-
Keep
*loadelements structurally simple:- The element with
*loadis cloned and used as-is. - Avoid relying on nested Sercrod directives inside the
*loadelement itself; keep its content mostly static (plain text or icons).
- The element with
-
Validate externally if needed:
*loaddoes basic JSON parsing only.- If you require more validation (schema checks, versioning), perform it in code that reacts to
sercrod-loaded.
Storage backends and adapters
The default *load.file path is intentionally simple: open a file picker, read JSON text, parse it, merge it into _stage or _data, dispatch sercrod-loaded, and update the host. *load.session and *load.store use the same merge step after reading JSON text from browser storage.
That does not mean *load is only a file-picker feature. The important boundary is the merge step. Built-in session/store forms or a file adapter can read JSON from another local source, then pass the parsed value into the same load path.
Useful browser storage patterns:
-
IndexedDB:
- Good for JSON snapshots, metadata, key-value records, and indexes.
- Good for remembering which saved item should be loaded later.
- Used by the built-in
*save.store/*load.storeJSON store. - Can also store Blob values, but host data should normally keep only a key and metadata.
- Use it as the default when the payload type does not clearly require a file-like store.
-
OPFS:
- Good for larger app-local payloads and file-like working directories.
- Good when the application needs an internal workspace rather than a user-visible downloaded file.
- Usually pairs well with IndexedDB metadata or indexes.
- Prefer it for obvious image payloads and suspiciously large Blob/File values, with IndexedDB metadata as the lookup record.
Recommended data shape:
- Keep host data JSON-like and render-friendly.
- Store large payloads outside host data.
- Keep keys, names, MIME types, sizes, timestamps, and status fields in host data.
- Let
*loadrestore the JSON state or source record that the template actually reads.
Do not create more backend-named directives just to name a storage backend. Prefer the action family (*save.file, *save.session, *save.store, and matching load forms), and put backend-specific behavior behind adapters or explicit helpers.
Examples
Full data import:
<serc-rod id="app" data='{"config":{"theme":"light","lang":"en"}}'>
<pre *literal="JSON.stringify(config, null, 2)"></pre>
<button type="button" *load.file>Load config…</button>
</serc-rod>
Partial import:
<serc-rod id="app" data='{"user":{},"settings":{}}'>
<button type="button" *load.file *keys="user settings">
Load user and settings
</button>
</serc-rod>
Custom accept type on a native file input:
<serc-rod id="app" data='{"user":{}}'>
<input type="file" accept="application/json,.json" *load.file *keys="user">
</serc-rod>
Notes
-
*load.fileandn-load.fileare aliases; choose one style for consistency. -
*load.sessionandn-load.sessionare aliases. -
*load.storeandn-load.storeare aliases. -
*loadandn-loadremain old compatible file-load spellings. -
*load.fileis designed for browser environments whereFileReaderand file dialogs are available. -
*load.storerequires IndexedDB. -
The directive expects JSON text; other content types will fail JSON parsing.
-
When JSON parsing fails and warnings are enabled, Sercrod logs a warning and does not modify data.
-
After a successful load, Sercrod dispatches a
sercrod-loadedevent:detail.stage:"load"for file/legacy loads,"load.session"for session loads, or"load.store"for store loads.detail.host: the Sercrod host elementdetail.fileName: the selected file name (ornull)detail.storage:"session"or"store"for non-file loads.detail.storageKey: the storage key for*load.sessionor*load.store.detail.response_target: the resolved*responsetarget.detail.response_key: the simple response destination key, ornull.detail.into: the legacy*intodestination key, ornull.detail.props: the property list used for partial merge (ornull)detail.keys: the same property list, provided for the unified action syntax.detail.json: the parsed JSON object
You can listen to this event on the host to perform additional validation or side effects.
-
For clarity and maintainability, avoid combining
*loadwith other I/O directives (*save,*post,*fetch) on the same element; use separate elements for each distinct action.