RecordEditor
Existing primitive form over a host-owned action with entity revision and explicit save/cancel.
Use the web element directly without the semantic runtime.
Use this component directly or compose it in application code.
The standard recipe resolver does not select this component automatically.
Import and live example#
An Ada record editor with name and reporting-period fields plus explicit entity revision.
Interactive preview requires JavaScript.
View the complete example source
import {registerAeliqoElements} from "@varendo/web";
import {
AeliqoBreakdownElement,
AeliqoComparisonElement,
AeliqoExplorerElement,
AeliqoFormFlowElement,
AeliqoInvestigationElement,
AeliqoQualityPanelElement,
AeliqoRecordEditorElement,
AeliqoSearchResultsElement,
} from "@varendo/web/compound";
import {AeliqoDateRangeElement, AeliqoTextFieldElement} from "@varendo/web/inputs";
import type {ResultRef, Scalar} from "@varendo/core";
import type {VisualizationBindingContext, VisualizationSpec} from "@varendo/core/visualization";
import type {AeliqoDataColumn, AeliqoDataScope, AeliqoFieldOption} from "@varendo/web/data";
import type {VisualizationDataset} from "@varendo/web/visualization";
const catalogRef: ResultRef = {
id: "aeliqo-catalog-example",
revision: "1",
outputId: "people",
queryDigest: "catalog-query",
scopeDigest: "catalog-scope",
};
const catalogRows: readonly Readonly<Record<string, Scalar>>[] = [
{id: "ada", name: "Ada Lovelace", team: "Research", date: "2026-09-08", amount: 120},
{id: "lin", name: "Lin Chen", team: "Product", date: "2026-09-09", amount: 96},
{id: "grace", name: "Grace Hopper", team: "Research", date: "2026-09-10", amount: 144},
];
const catalogColumns: readonly AeliqoDataColumn[] = [
{key: "id", label: "ID", type: "text", sortable: true},
{key: "name", label: "Name", type: "text", sortable: true},
{key: "team", label: "Team", type: "text"},
{key: "date", label: "Date", type: "date", sortable: true},
{key: "amount", label: "Amount", type: "integer", align: "end"},
];
const catalogFields: readonly AeliqoFieldOption[] = [
{id: "name", label: "Name", type: "text"},
{id: "team", label: "Team", type: "text"},
{id: "amount", label: "Amount", type: "integer"},
];
const catalogScope: AeliqoDataScope = {loaded: catalogRows.length, filteredTotal: catalogRows.length, populationDigest: catalogRef.scopeDigest, kind: "filtered", label: "Authorized people"};
const catalogVisualizationContext: VisualizationBindingContext = {results: []};
const catalogVisualizationDataset: VisualizationDataset = {result: catalogRef, rows: catalogRows};
const catalogVisualizationSpecs: Readonly<Record<"trend", VisualizationSpec>> = {trend: {version: "1", view: "trend", plot: {version: "1", root: {kind: "unit", mark: "line", result: catalogRef, missing: "gap", encoding: {x: {field: "date", scale: "temporal"}, y: {field: "amount", scale: "linear"}}}}}};
registerAeliqoElements();
const host = document.querySelector<HTMLElement>("#aeliqo-example") ?? (() => {
const created = document.createElement("div");
created.id = "aeliqo-example";
(document.body ?? document.documentElement).append(created);
return created;
})();
function createCatalogRoot(container: HTMLElement): HTMLElement {
const root = document.createElement("div");
root.dataset.catalogSourceRoot = "true";
root.style.display = "grid";
root.style.gap = "12px";
container.append(root);
return root;
}
function createCatalogElement<T extends HTMLElement>(tagName: string, container: HTMLElement): T {
const element = document.createElement(tagName) as T;
element.setAttribute("data-aeliqo-theme", "light");
container.append(element);
return element;
}
function appendSlottedText(root: HTMLElement, slot: string, textContent: string): void {
const content = document.createElement("span");
content.slot = slot;
content.textContent = textContent;
root.append(content);
}
const root = createCatalogRoot(host);
(((root) => {
const element = createCatalogElement<AeliqoRecordEditorElement>("aeliqo-record-editor", root);
element.entity = "person";
element.entityKey = "string:3:ada";
element.entityRevision = "person-revision-1";
const name = document.createElement("aeliqo-text-field") as AeliqoTextFieldElement;
name.label = "Name";
name.name = "name";
name.value = "Ada Lovelace";
const period = document.createElement("aeliqo-date-range") as AeliqoDateRangeElement;
period.label = "Review period";
period.name = "period";
period.start = "2026-09-01";
period.end = "2026-09-30";
element.append(name, period);
}))(root);
Purpose#
RecordEditor wraps slotted fields with a record key, revision, and save/cancel actions. Use it when edits must carry version evidence to a host-owned action.
When to use it#
- An existing record is edited and its revision must travel with the save.
- Save must validate the fields first and emit a proposal, never persist directly.
- Cancel must emit the same record context so the host can discard cleanly.
- The host owns the action, conflict handling, and resulting effect.
When to use a different component#
- Use Form for submissions without entity identity or revision.
- Use FormFlow for multi-step entry with drafts and review.
- Use Detail for read-only record display.
Properties and defaults#
The entity key and revision are required evidence for save/cancel requests; the host authorizes the resulting action.
| Property | Use and ownership | Declared type | Initial value |
|---|---|---|---|
entity | Names the catalog entity whose records and identities are displayed. | string | 'record' |
entityKey | Supplies entity key to the component as application-owned input. | string | '' |
entityRevision | Identifies the entity version so stale state can be detected explicitly. | string | '' |
action | Identifies the registered action proposed by this control. Application code authorizes and executes it. | VersionRef | undefined | undefined |
status | Supplies the explicit ready, loading, empty, partial, stale, or error state. | AeliqoCompoundStatus | 'ready' |
message | Provides the user-facing status, error, or recovery message. | string | '' |
title | Provides the visible title for the current data or compound surface. | string | 'Edit record' |
disabled | Prevents user interaction while keeping the control and its current value visible. | boolean | false |
invalid | Marks the current editor state invalid and blocks a valid save proposal. | boolean | false |
saveLabel | Provides the visible text for the save control or section. | string | 'Save' |
cancelLabel | Provides the visible text for the cancel control or section. | string | 'Cancel' |
Events#
| Event | Payload | Emitted | Application responsibility |
|---|---|---|---|
aeliqo-record-editor-save | The entity key, revision, action reference, and validated draft. | After the user requests save from a valid editor. | Recheck revision and authority, execute the action, and report the outcome. |
aeliqo-record-editor-cancel | The entity key, revision, and current draft context. | After the user cancels editing. | Keep or discard the draft by application policy and restore focus. |
Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.
Listen for aeliqo-record-editor-save
const element = document.querySelector('aeliqo-record-editor');<p>element?.addEventListener('aeliqo-record-editor-save', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-record-editor-cancel
const element = document.querySelector('aeliqo-record-editor');</p>
<p>element?.addEventListener('aeliqo-record-editor-cancel', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});States and failure handling#
Relevant states:
- ready
- invalid
- pending
- error
- disabled
Expected result: The editor validates its fields and emits a versioned save or cancel proposal without persisting it.
Keyboard, focus, and accessibility#
Keyboard behavior:
- Tab follows slotted field order
- Enter on save
- Escape or cancel preserves draft
- IME composition
Exposed semantics:
- aria-label
- button
- role
- section
Responsive behavior#
Stack fields at narrow widths. Keep the entity identity and revision associated with Save and Cancel.
Style hooks#
- Shadow parts:
actions,form,header,meta,root,status - Varendo design tokens referenced:
--aeliqo-space-12
Related components#
Generated TypeScript declaration#
View generated declaration
export declare class AeliqoRecordEditorElement extends AeliqoCompoundElement {
static readonly properties: {
entity: {
type: StringConstructor;
};
entityKey: {
attribute: string;
type: StringConstructor;
};
entityRevision: {
attribute: string;
type: StringConstructor;
};
action: {
attribute: boolean;
};
status: {
type: StringConstructor;
};
message: {
type: StringConstructor;
};
title: {
type: StringConstructor;
};
disabled: {
type: BooleanConstructor;
};
invalid: {
type: BooleanConstructor;
};
saveLabel: {
attribute: string;
type: StringConstructor;
};
cancelLabel: {
attribute: string;
type: StringConstructor;
};
};
static readonly styles: import("lit").CSSResult[];
entity: string;
entityKey: string;
entityRevision: string;
action: VersionRef | undefined;
status: AeliqoCompoundStatus;
message: string;
title: string;
disabled: boolean;
invalid: boolean;
saveLabel: string;
cancelLabel: string;
protected render(): import("lit").TemplateResult<1>;
private readonly save;
private readonly cancel;
}Version#
This page documents the Varendo 0.6 component contract.
