Table
Native table first; separate interactive-grid mode; sorting, paging, selection, virtualization and precise values.
Use the web element directly without the semantic runtime.
A registered presentation adapter can bind this component to host-owned meaning and state.
A standard recipe can select this component when its task, bindings, data, and policy are eligible.
Import and live example#
A captioned people table with identity selection, sortable columns, and a bounded page.
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<AeliqoTableElement>("aeliqo-table", root);
element.caption = "People";
element.columns = tableColumns;
element.rows = tableRows;
element.identity = ["id"];
element.entity = "person";
element.selection = "multiple";
element.selectedKeys = [personKeys[0]];
element.result = catalogRef;
element.page = 1;
element.pageSize = 10;
element.totalRows = catalogRows.length;
element.scope = catalogScope;
}))(root);
Purpose#
Show rows and columns in a native table, with an opt-in grid mode for cell navigation. Sorting, paging, and selection are requests the application answers.
When to use it#
- Compare exact values across many columns.
- Sort or page rows while the host owns the data.
- Select rows by stable identity.
- Handle large result sets through bounded pages or virtualization.
When to use a different component#
- Use RecordList for compact browsing without column comparison.
- Use SelectionSummary to report a selection rather than display rows.
Properties and defaults#
Table remains native by default; mode and virtualization are explicit host choices with stable row identity.
| Property | Use and ownership | Declared type | Initial value |
|---|---|---|---|
columns | Defines ordered visible fields, labels, formatting, alignment, and supported column interactions. | readonly AeliqoTableColumn[] | [] |
rows | Supplies the bounded records to render. The component never fetches or widens this set. | readonly AeliqoTableRow[] | [] |
caption | Provides the visible table caption and accessible name for the data relationship. | string | '' |
emptyLabel | Provides the text shown when no value or row is available. | string | 'No rows to display.' |
entity | Names the catalog entity whose records and identities are displayed. | string | 'row' |
identity | Lists stable identity fields used for selection, detail targeting, and state transfer. | readonly string[] | [] |
selection | Chooses none, single, or multiple selection behavior. | AeliqoTableSelectionMode | 'none' |
selectedKeys | Controls the current collection selection using stable encoded identities. | readonly string[] | [] |
result | Supplies the Result reference that binds displayed data to its query and scope evidence. | ResultRef | undefined | undefined |
mode | Supplies mode to the component as application-owned input. | AeliqoTableMode | 'table' |
sort | Supplies the current table sort so controls reflect authoritative host state. | AeliqoSortState | undefined | undefined |
page | Controls the current one-based page. | number | 1 |
pageSize | Sets the number of rows represented by one table page. | number | 0 |
totalRows | Provides the total known row count used for paging and scope disclosure. | number | undefined | undefined |
virtualized | Enables explicit windowed table rendering for large bounded results. | boolean | false |
virtualStart | Sets the first row index represented by the supplied virtual window. | number | 0 |
virtualCount | Sets the total virtual row count represented by the current window. | number | 40 |
overscan | Sets the extra virtualized rows rendered outside the visible window. | number | 4 |
scope | Supplies the visible authorization and population scope associated with the displayed value or rows. | AeliqoDataScope | undefined | undefined |
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-table-selection | Stable selected identity keys plus result lineage. | After table selection changes. | Validate scope and update controlled selectedKeys. |
aeliqo-table-sort | The requested column and direction. | After a sortable column header is activated. | Apply sorting in the data owner, then update rows and controlled sort. |
aeliqo-table-page | The requested page and page size. | After table paging controls are activated. | Fetch or select that page, then update rows, Result evidence, and page. |
aeliqo-table-window | The requested virtual start and count. | When scrolling requires another virtual row window. | Load the bounded window and update rows, virtualStart, and virtualCount. |
Events cross the component boundary as user proposals. Validate their detail and current authority before applying a business effect.
Listen for aeliqo-table-selection
const element = document.querySelector('aeliqo-table');<p>element?.addEventListener('aeliqo-table-selection', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-table-sort
const element = document.querySelector('aeliqo-table');</p>
<p>element?.addEventListener('aeliqo-table-sort', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-table-page
const element = document.querySelector('aeliqo-table');</p>
<p>element?.addEventListener('aeliqo-table-page', (event) => {
const proposal = (event as CustomEvent<unknown>).detail;
// Validate the proposal, update host state, then assign controlled properties.
applyProposal(proposal);
});Listen for aeliqo-table-window
const element = document.querySelector('aeliqo-table');</p>
<p>element?.addEventListener('aeliqo-table-window', (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
- empty
- loading
- partial
- stale
- error
Expected result: The table preserves caption, scope, sort/page requests, and selection identity without losing keyboard access.
Keyboard, focus, and accessibility#
Keyboard behavior:
- Tab
- Enter
- Space
- Arrow keys in grid mode
Exposed semantics:
- aria-colcount
- aria-colindex
- aria-colspan
- aria-label
- aria-pressed
- aria-rowcount
- aria-rowindex
- aria-selected
- aria-sort
- button
- caption
- input
- nav
- role
- table
- tbody
- td
- th
- thead
- tr
Responsive behavior#
Use the table’s bounded page or virtualization controls with wide data. Keep a scroll path or choose a compact view before labels become unreadable.
Style hooks#
- Shadow parts:
empty,grid,grid-body,grid-head,grid-row,heading,next,page-status,pagination,previous,scope,scroll,selection-cell,selection-heading,sort,status,table - Varendo design tokens referenced:
--aeliqo-color-accent,--aeliqo-color-border,--aeliqo-color-canvas,--aeliqo-color-danger,--aeliqo-color-focus,--aeliqo-color-muted,--aeliqo-color-surface,--aeliqo-color-text,--aeliqo-color-warning,--aeliqo-control-border-width,--aeliqo-control-compact-target,--aeliqo-focus-offset,--aeliqo-focus-width,--aeliqo-radius-medium,--aeliqo-radius-small,--aeliqo-space-12,--aeliqo-space-16,--aeliqo-space-4,--aeliqo-space-8,--aeliqo-table-color,--aeliqo-table-focus,--aeliqo-table-heading-background,--aeliqo-table-rule,--aeliqo-typography-font-size-caption,--aeliqo-typography-font-weight-semibold
Performance limits#
- Public workload controls: `pageSize` (default 0), `virtualized` (default false), `virtualStart` (default 0), `virtualCount` (default 40), `overscan` (default 4).
- The source-defined `AELIQO_TABLE_MAX_VIRTUAL_ROWS` limit is 100.
Related components#
Generated TypeScript declaration#
View generated declaration
export declare class AeliqoTableElement extends LitElement {
static readonly aeliqoVersion = "0.1.0";
static readonly properties: {
columns: {
attribute: boolean;
};
rows: {
attribute: boolean;
};
caption: {
type: StringConstructor;
};
emptyLabel: {
attribute: string;
type: StringConstructor;
};
entity: {
type: StringConstructor;
};
identity: {
attribute: boolean;
};
selection: {
type: StringConstructor;
};
selectedKeys: {
attribute: boolean;
};
result: {
attribute: boolean;
};
mode: {
type: StringConstructor;
};
sort: {
attribute: boolean;
};
page: {
type: NumberConstructor;
};
pageSize: {
attribute: string;
type: NumberConstructor;
};
totalRows: {
attribute: string;
type: NumberConstructor;
};
virtualized: {
type: BooleanConstructor;
};
virtualStart: {
attribute: string;
type: NumberConstructor;
};
virtualCount: {
attribute: string;
type: NumberConstructor;
};
overscan: {
type: NumberConstructor;
};
scope: {
attribute: boolean;
};
status: {
type: StringConstructor;
};
message: {
type: StringConstructor;
};
};
columns: readonly AeliqoTableColumn[];
rows: readonly AeliqoTableRow[];
caption: string;
emptyLabel: string;
entity: string;
identity: readonly string[];
selection: AeliqoTableSelectionMode;
selectedKeys: readonly string[];
result: ResultRef | undefined;
mode: AeliqoTableMode;
sort: AeliqoSortState | undefined;
page: number;
pageSize: number;
totalRows: number | undefined;
virtualized: boolean;
virtualStart: number;
virtualCount: number;
overscan: number;
scope: AeliqoDataScope | undefined;
status: AeliqoDataStatus;
message: string;
protected render(): import("lit").TemplateResult<1>;
private renderTable;
private renderCaption;
private renderTableHead;
private renderTableRows;
private renderEmptyRow;
private renderHeader;
private renderTableRow;
private renderGrid;
private renderGridRow;
private renderGridCell;
private renderGridHeader;
private gridTemplate;
private renderSelectionCell;
private selectionLabelForKey;
private gridColumnCount;
private virtualWindow;
private visibleRows;
private readonly requestSort;
private readonly requestPage;
private readonly handleSelection;
private gridFocus;
private pendingGridFocus;
protected updated(): void;
private resolveGridFocus;
private keyedGridRow;
private fallbackGridRow;
private rememberGridFocus;
private rowKeyAt;
private gridFocusAt;
private findGridCell;
private availableRowCount;
private gridNavigationContext;
private requestGridWindow;
private readonly handleGridCellKeyDown;
private requestVirtualGridFocus;
static readonly styles: import("lit").CSSResult[];
}Version#
This page documents the Varendo 0.6 component contract.
