// DataTable demo. Route: /table // // Two tables: one over a local array, one backed by /api/accounts. // // The remote table does not receive a fetch function. Component props travel // as HTML attributes, so a function passed that way arrives as its own source // text rather than something callable. Instead the table emits a `request` // output and we answer it by dispatching the rows back with the same id. page TablePage { state localRows = [ { id: 1, name: "Northwind", plan: "Scale", seats: 42, renewsOn: "2026-02-09" }, { id: 2, name: "Acme Industrial", plan: "Team", seats: 8, renewsOn: "2026-01-10" }, { id: 3, name: "Globex", plan: "Enterprise", seats: 210, renewsOn: "2025-12-24" }, { id: 4, name: "Initech", plan: "Starter", seats: 5, renewsOn: "2026-03-02" }, { id: 5, name: "Umbrella", plan: "Scale", seats: 96, renewsOn: "2026-01-31" } ] state localColumns = [ { key: "name", label: "Account", sortable: true }, { key: "plan", label: "Plan", sortable: true }, { key: "seats", label: "Seats", align: "end", sortable: true, type: "number" }, { key: "renewsOn", label: "Renews", align: "end", sortable: true, type: "date" } ] state remoteColumns = [ { key: "name", label: "Account", sortable: true }, { key: "owner", label: "Owner", sortable: true }, { key: "plan", label: "Plan", align: "center" }, { key: "seats", label: "Seats", align: "end", sortable: true, type: "number" }, { key: "renewsOn", label: "Renews", align: "end", sortable: true, type: "date" } ] state tableActions = [] state lastEvent = "none yet" functions { // The table asks for rows through its `request` output; we answer by // dispatching the result back with the same instanceId. It cannot simply // call a function we hand it: component props travel as HTML attributes, // so a function would arrive as its own source text. function loadAccounts(payload) { var id = payload.instanceId var search = new URLSearchParams({ page: String(payload.page), pageSize: String(payload.pageSize), query: payload.query || "", sortKey: payload.sortKey || "", sortDirection: payload.sortDirection || "asc" }) fetch("/api/accounts?" + search.toString()) .then(function (response) { if (!response.ok) { throw new Error("Request failed with status " + response.status) } return response.json() }) .then(function (data) { window.dispatchEvent(new CustomEvent("wrnexus:datatable:rows", { detail: { instanceId: id, rows: data.rows, total: data.total } })) }) .catch(function (error) { window.dispatchEvent(new CustomEvent("wrnexus:datatable:error", { detail: { instanceId: id, message: error.message } })) }) } function onTableChange(payload) { lastEvent = "page " + payload.page + " of " + Math.max(1, Math.ceil(payload.total / payload.pageSize)) + " · " + payload.total + " records" + (payload.sortKey ? " · sorted by " + payload.sortKey + " " + payload.sortDirection : "") } function onTableAction(payload) { toast.info(payload.id + " on " + payload.rows.length + " record(s)") } } style { .table-demo-section { display: grid; gap: 0.75rem; margin-top: 2rem; } .table-demo-note { margin: 0; color: var(--wrn-color-text-muted); font-size: 0.82rem; } .table-demo-note code { color: var(--wrn-color-text); } } view {

Data table

Sorting, filtering, paging and selection over a local array, and the same component driven by an API through its request output.

Local array

Everything is derived in the browser. The Renews column declares type: "date", so it sorts chronologically rather than alphabetically.

Loaded from an API

With remote the table emits a request for each view change and waits to be handed rows back. Sorting and searching are done by /api/accounts — the table never sees the other pages.

Last change event: {lastEvent}

} }