FilterBuilder
Typed predicates, AND/OR/null handling, visible inherited scope and explicit query application.
Use the web element directly without the semantic runtime.
A registered presentation adapter can bind this component to host-owned meaning and state.
The standard recipe resolver does not select this component automatically.
Import and live example#
One unapplied team equals Research clause against authorized people fields.
Interactive preview requires JavaScript.
View the complete example source
import {registerAeliqoElements} from "@varendo/web";
import {
AeliqoCardCollectionElement,
AeliqoDeltaElement,
AeliqoDetailElement,
AeliqoFilterBuilderElement,
AeliqoKeyValueElement,
AeliqoMetricElement,
AeliqoRecordListElement,
AeliqoSelectionSummaryElement,
AeliqoTableElement,
type AeliqoKeyValueItem,
type AeliqoTableColumn,
type AeliqoTableRow,
} from "@varendo/web/data";
import type {ResultRef,
Scalar,
} from "@varendo/core";
import type {AeliqoDataColumn, AeliqoDataScope, AeliqoFieldOption} from "@varendo/web/data";
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 tableColumns: readonly AeliqoTableColumn[] = catalogColumns.map(({key, label, sortable, align}) => ({key, label, ...(sortable === undefined ? {} : {sortable}), ...(align === undefined ? {} : {align})}));
const tableRows: readonly AeliqoTableRow[] = catalogRows.map((row) => ({id: row.id ?? null, name: row.name ?? null, team: row.team ?? null, date: row.date ?? null, amount: row.amount ?? null}));
const personKeys = ["string:3:ada", "string:5:grace"] as const;
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<AeliqoFilterBuilderElement>("aeliqo-filter-builder", root);
element.fields = catalogFields;
element.entity = "person";
element.scopeLabel = "Authorized people";
element.autoApply = false;
element.clauses = [{
field: "team",
operator: "eq",
value: "Research"
}];
element.logical = "and";
}))(root);
Purpose#
Build filter clauses from allowed fields and operators. Apply emits a request; the application authorizes and runs the query.
When to use it#
- Let people compose typed field clauses with AND/OR logic.
- Keep inherited filters visible next to the local draft.
- Delay execution until an explicit Apply request.
When to use a different component#
- Use SelectionSummary to report the active selection instead of editing it.
- Use Table to browse and sort the filtered rows.
Properties and defaults#
Draft clauses are local until Apply; autoApply remains an explicit host choice and does not run a query itself.
| Property | Use and ownership | Declared type | Initial value |
|---|---|---|---|
fields | Defines the fields available to this control, including stable IDs, labels, and declared types. | readonly AeliqoFieldOption[] | [] |
predicate | Supplies the validated filter predicate represented by the current control state. | AeliqoFilterPredicate | undefined | undefined |
inherited | Supplies read-only predicates inherited from an outer application scope. | AeliqoFilterPredicate | undefined | undefined |
entity | Names the catalog entity whose records and identities are displayed. | string | '' |
scopeLabel | Provides the visible text for the scope control or section. | string | 'Current authorized scope' |
applyLabel | Provides the visible text for the apply control or section. | string | 'Apply filter' |
autoApply | Enables or disables auto apply as explicit host-controlled state. | boolean | false |
clauses | Supplies the current filter clauses. Application code owns query execution and authoritative filter state. | readonly AeliqoFilterClause[] | [] |
logical | Chooses whether filter clauses are joined with AND or OR. | 'and' | 'or' | 'and' |
status | Supplies the explicit ready, loading, empty, partial, stale, or error state. | AeliqoDataStatus | 'ready' |
message | Provides the user-facing status, error, or recovery message. | string | '' |
Events#
| Event | Payload | Emitted | Application responsibility |
|---|---|---|---|
aeliqo-filter-change | The typed predicate and filter state. | After Apply, or after a valid change when auto-apply is enabled. | Validate and evaluate the predicate, then update rows and Result evidence. |
Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.
Listen for aeliqo-filter-change
const element = document.querySelector('aeliqo-filter-builder');<p>element?.addEventListener('aeliqo-filter-change', (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
Expected result: The builder validates a typed predicate and emits it only after an explicit apply request.
Keyboard, focus, and accessibility#
Keyboard behavior:
- Tab
- Arrow keys
- Enter
- Escape
- IME composition
Exposed semantics:
- aria-label
- button
- form
- input
- role
- select
Responsive behavior#
Stack field, operator, and value controls when space is limited. Keep Apply reachable and preserve the active draft.
Style hooks#
- Shadow parts:
add-condition,apply,builder,clause,clauses,field,field-label,inherited-predicate,logical,logical-label,operator,operator-label,remove-condition,scope,status,unsupported-predicate,validation,value,value-label - Varendo design tokens referenced:
--aeliqo-color-accent,--aeliqo-color-border,--aeliqo-color-danger,--aeliqo-color-muted,--aeliqo-color-on-accent,--aeliqo-color-surface,--aeliqo-color-surface-muted,--aeliqo-color-warning,--aeliqo-control-border-width,--aeliqo-control-min-target,--aeliqo-radius-small,--aeliqo-space-4,--aeliqo-space-8,--aeliqo-typography-font-size-caption,--aeliqo-typography-font-weight-semibold
Related components#
Generated TypeScript declaration#
View generated declaration
export declare class AeliqoFilterBuilderElement extends LitElement {
static readonly aeliqoVersion = "0.1.0";
static readonly properties: {
fields: {
attribute: boolean;
};
predicate: {
attribute: boolean;
};
inherited: {
attribute: boolean;
};
entity: {
type: StringConstructor;
};
scopeLabel: {
attribute: string;
type: StringConstructor;
};
applyLabel: {
attribute: string;
type: StringConstructor;
};
autoApply: {
attribute: string;
type: BooleanConstructor;
};
clauses: {
attribute: boolean;
};
logical: {
type: StringConstructor;
};
status: {
type: StringConstructor;
};
message: {
type: StringConstructor;
};
};
fields: readonly AeliqoFieldOption[];
predicate: AeliqoFilterPredicate | undefined;
inherited: AeliqoFilterPredicate | undefined;
entity: string;
scopeLabel: string;
applyLabel: string;
autoApply: boolean;
clauses: readonly AeliqoFilterClause[];
logical: 'and' | 'or';
status: AeliqoDataStatus;
message: string;
private clauseDrafts;
private logicalMode;
private unsupportedPredicate;
private draftSourceSignature;
private draftInitialized;
private draftInteracted;
private validationMessage;
protected willUpdate(changed: Map<string, unknown>): void;
protected render(): import("lit").TemplateResult<1>;
private shouldProjectDraft;
private currentProjection;
private currentProjectionSignature;
private replaceDraft;
private seedDraftWhenFieldsArrive;
private isUnavailable;
private renderClauses;
private renderLogicalControl;
private renderAddCondition;
private renderUnsupportedPredicate;
private renderInheritedPredicate;
private renderApplyButton;
private renderValidationMessage;
private renderStatus;
private renderClause;
private clauseNeedsValue;
private clauseIndex;
private updateClause;
private readonly handleAddCondition;
private readonly handleRemoveCondition;
private readonly handleFieldChange;
private readonly handleOperatorChange;
private readonly handleValueInput;
private readonly handleLogicalChange;
private readonly handleSubmit;
private readonly apply;
private buildPredicate;
static readonly styles: import("lit").CSSResult[];
}Version#
This page documents the Varendo 0.6 component contract.
