Comparison
A stable compare-set with compatible metrics and simultaneous comparison affordances.
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#
A two-person comparison with amount metrics in one authorized scope.
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<AeliqoComparisonElement>("aeliqo-comparison", root);
element.compareSet = [{
key: "ada",
label: "Ada"
}, {
key: "grace",
label: "Grace"
}];
element.compareKeys = ["ada", "grace"];
element.entity = "person";
element.metrics = [{
id: "amount",
label: "Amount",
unit: "records",
values: {
ada: 120,
grace: 144
}
}, {
id: "team",
label: "Team",
values: {
ada: "Research",
grace: "Research"
}
}];
element.result = catalogRef;
element.scope = catalogScope;
}))(root);
Purpose#
Comparison places a small set of chosen entities side by side across supplied metrics. Use it when people must weigh a few records at once.
When to use it#
- A bounded set of entities needs the same metrics shown side by side.
- The host has declared the metrics compatible in units and grain.
- Compare-set changes must reach the host as a typed proposal.
- Values are precomputed; the view must not recalculate them or infer causes.
When to use a different component#
- Use Breakdown to compare host-defined groups instead of chosen entities.
- Use Table when users need to scan or sort the underlying records.
- Use Metric for a single value with no compare set.
Properties and defaults#
Comparison keys and compatible metric meanings are host supplied; the component does not infer a causal difference.
| Property | Use and ownership | Declared type | Initial value |
|---|---|---|---|
compareKeys | Supplies the bounded ordered compare keys collection used by this component. | readonly string[] | [] |
compareSet | Supplies the bounded ordered compare set collection used by this component. | readonly { readonly key: string; readonly label?: string }[] | [] |
metrics | Supplies the declared metrics shown in the comparison, including compatible meaning and units. | readonly AeliqoComparisonMetric[] | [] |
entity | Names the catalog entity whose records and identities are displayed. | string | 'record' |
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 | 'Comparison' |
result | Supplies the Result reference that binds displayed data to its query and scope evidence. | ResultRef | undefined | undefined |
scope | Supplies the visible authorization and population scope associated with the displayed value or rows. | AeliqoDataScope | undefined | undefined |
identity | Lists stable identity fields used for selection, detail targeting, and state transfer. | readonly string[] | [] |
compatible | States whether compared values share compatible meaning and units. The host computes this fact. | boolean | true |
selectedKey | Controls the current record selection by stable encoded identity. | string | '' |
Events#
| Event | Payload | Emitted | Application responsibility |
|---|---|---|---|
aeliqo-comparison-set | The proposed bounded comparison identity set. | After the user changes compared records. | Validate compatible identities and update the controlled comparison set. |
Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.
Listen for aeliqo-comparison-set
const element = document.querySelector('aeliqo-comparison');<p>element?.addEventListener('aeliqo-comparison-set', (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
- partial
- stale
- error
- invalid
Expected result: The selected comparison set stays bounded and emits a typed set request with scope lineage.
Keyboard, focus, and accessibility#
Keyboard behavior:
- Tab
- Arrow keys across comparison controls
- Enter or Space
Exposed semantics:
- aria-label
- aria-pressed
- button
- role
- section
Responsive behavior#
Keep every compared entity and metric in view. Stack comparison rows or allow a local scroll area instead of dropping values.
Style hooks#
- Shadow parts:
actions,compare-button,header,hint,root,scope,status,table - Varendo design tokens referenced: none referenced directly by this class lineage.
Performance limits#
- The source-defined `MAX_COMPARISON_KEYS` limit is 32.
- The source-defined `MAX_COMPARISON_METRICS` limit is 64.
Related components#
Generated TypeScript declaration#
View generated declaration
export declare class AeliqoComparisonElement extends AeliqoCompoundElement {
static readonly properties: {
compareKeys: {
attribute: boolean;
};
compareSet: {
attribute: boolean;
};
metrics: {
attribute: boolean;
};
entity: {
type: StringConstructor;
};
status: {
type: StringConstructor;
};
message: {
type: StringConstructor;
};
title: {
type: StringConstructor;
};
result: {
attribute: boolean;
};
scope: {
attribute: boolean;
};
identity: {
attribute: boolean;
};
compatible: {
type: BooleanConstructor;
};
selectedKey: {
attribute: string;
type: StringConstructor;
};
};
static readonly styles: import("lit").CSSResult[];
compareKeys: readonly string[];
compareSet: readonly {
readonly key: string;
readonly label?: string;
}[];
metrics: readonly AeliqoComparisonMetric[];
entity: string;
status: AeliqoCompoundStatus;
message: string;
title: string;
result: ResultRef | undefined;
scope: AeliqoDataScope | undefined;
identity: readonly string[];
compatible: boolean;
selectedKey: string;
protected render(): import("lit").TemplateResult<1>;
private readonly requestCompare;
}Version#
This page documents the Varendo 0.6 component contract.
