Varendo

Comparison

A stable compare-set with compatible metrics and simultaneous comparison affordances.

FamilycompoundLicenseApache-2.0
StandaloneAvailable

Use the web element directly without the semantic runtime.

Semantic bindingNo built-in binding

Use this component directly or compose it in application code.

Automatic adaptationNo standard recipe

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

When to use a different component

Properties and defaults

Comparison keys and compatible metric meanings are host supplied; the component does not infer a causal difference.

Properties, ownership, and initial values
PropertyUse and ownershipDeclared typeInitial value
compareKeysSupplies the bounded ordered compare keys collection used by this component.readonly string[][]
compareSetSupplies the bounded ordered compare set collection used by this component.readonly { readonly key: string; readonly label?: string }[][]
metricsSupplies the declared metrics shown in the comparison, including compatible meaning and units.readonly AeliqoComparisonMetric[][]
entityNames the catalog entity whose records and identities are displayed.string'record'
statusSupplies the explicit ready, loading, empty, partial, stale, or error state.AeliqoCompoundStatus'ready'
messageProvides the user-facing status, error, or recovery message.string''
titleProvides the visible title for the current data or compound surface.string'Comparison'
resultSupplies the Result reference that binds displayed data to its query and scope evidence.ResultRef | undefinedundefined
scopeSupplies the visible authorization and population scope associated with the displayed value or rows.AeliqoDataScope | undefinedundefined
identityLists stable identity fields used for selection, detail targeting, and state transfer.readonly string[][]
compatibleStates whether compared values share compatible meaning and units. The host computes this fact.booleantrue
selectedKeyControls the current record selection by stable encoded identity.string''

Events

Events, payloads, timing, and application responsibilities
EventPayloadEmittedApplication responsibility
aeliqo-comparison-setThe 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

TypeScript example
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:

Expected result: The selected comparison set stays bounded and emits a typed set request with scope lineage.

Keyboard, focus, and accessibility

Keyboard behavior:

Exposed semantics:

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

Performance limits

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.