DataTable

Advanced data table with sorting, filtering, and pagination

DataTable

A feature-rich data table component with sorting, filtering, pagination, and row selection.

Basic Usage

json
{
  "kind": "component",
  "name": "DataTable",
  "props": {
    "data": { "expr": "state", "name": "users" },
    "columns": { "expr": "lit", "value": [
      { "key": "name", "title": "Name" },
      { "key": "email", "title": "Email" },
      { "key": "role", "title": "Role" }
    ]}
  }
}

Props

PropTypeDefaultDescription
dataExpression[]Data array
columnsExpression[]Column definitions
pageSizeExpression10Rows per page
pageExpression1Current page
sortableExpressionfalseEnable sorting
filterableExpressionfalseEnable filtering
selectableExpressionfalseEnable row selection
selectedRowsExpression[]Selected row keys
rowKeyExpression"id"Key field for rows
loadingExpressionfalseLoading state
emptyTextExpression"No data"Empty state text
onSortEventHandler-Sort change handler
onFilterEventHandler-Filter change handler
onPageChangeEventHandler-Page change handler
onSelectionChangeEventHandler-Selection change handler

Column Definition

typescript
interface Column {
  key: string;
  title: string;
  sortable?: boolean;
  filterable?: boolean;
  width?: string | number;
  align?: 'left' | 'center' | 'right';
  render?: ViewNode;
  filterType?: 'text' | 'select' | 'date' | 'number';
  filterOptions?: { label: string; value: string }[];
}

Examples

Full-Featured Table

json
{
  "version": "1.0",
  "state": {
    "users": {
      "type": "list",
      "initial": [
        { "id": 1, "name": "John Doe", "email": "john@example.com", "role": "Admin", "status": "active" },
        { "id": 2, "name": "Jane Smith", "email": "jane@example.com", "role": "User", "status": "active" },
        { "id": 3, "name": "Bob Wilson", "email": "bob@example.com", "role": "User", "status": "inactive" }
      ]
    },
    "page": { "type": "number", "initial": 1 },
    "sort": { "type": "object", "initial": { "key": "name", "direction": "asc" } },
    "filters": { "type": "object", "initial": {} },
    "selected": { "type": "list", "initial": [] }
  },
  "actions": [
    {
      "name": "handleSort",
      "steps": [{ "do": "set", "target": "sort", "value": { "expr": "var", "name": "payload" } }]
    },
    {
      "name": "handleFilter",
      "steps": [{ "do": "set", "target": "filters", "value": { "expr": "var", "name": "payload" } }]
    },
    {
      "name": "handlePageChange",
      "steps": [{ "do": "set", "target": "page", "value": { "expr": "var", "name": "payload" } }]
    },
    {
      "name": "handleSelectionChange",
      "steps": [{ "do": "set", "target": "selected", "value": { "expr": "var", "name": "payload" } }]
    }
  ],
  "view": {
    "kind": "component",
    "name": "DataTable",
    "props": {
      "data": { "expr": "state", "name": "users" },
      "columns": { "expr": "lit", "value": [
        { "key": "name", "title": "Name", "sortable": true, "filterable": true },
        { "key": "email", "title": "Email", "sortable": true, "filterable": true },
        { "key": "role", "title": "Role", "sortable": true, "filterable": true, "filterType": "select", "filterOptions": [
          { "label": "Admin", "value": "Admin" },
          { "label": "User", "value": "User" }
        ]},
        { "key": "status", "title": "Status", "sortable": true }
      ]},
      "pageSize": { "expr": "lit", "value": 10 },
      "page": { "expr": "state", "name": "page" },
      "sortable": { "expr": "lit", "value": true },
      "filterable": { "expr": "lit", "value": true },
      "selectable": { "expr": "lit", "value": true },
      "selectedRows": { "expr": "state", "name": "selected" },
      "onSort": { "event": "sort", "action": "handleSort" },
      "onFilter": { "event": "filter", "action": "handleFilter" },
      "onPageChange": { "event": "pageChange", "action": "handlePageChange" },
      "onSelectionChange": { "event": "selectionChange", "action": "handleSelectionChange" }
    }
  }
}

Custom Cell Rendering

json
{
  "columns": [
    {
      "key": "status",
      "title": "Status",
      "render": {
        "kind": "element",
        "tag": "span",
        "props": {
          "className": {
            "expr": "cond",
            "if": { "expr": "bin", "op": "==", "left": { "expr": "var", "name": "value" }, "right": { "expr": "lit", "value": "active" } },
            "then": { "expr": "lit", "value": "badge badge-success" },
            "else": { "expr": "lit", "value": "badge badge-gray" }
          }
        },
        "children": [{ "kind": "text", "value": { "expr": "var", "name": "value" } }]
      }
    }
  ]
}

Server-Side Operations

json
{
  "actions": [
    {
      "name": "fetchData",
      "steps": [{
        "do": "fetch",
        "url": {
          "expr": "concat",
          "items": [
            { "expr": "lit", "value": "/api/users?page=" },
            { "expr": "state", "name": "page" },
            { "expr": "lit", "value": "&sort=" },
            { "expr": "get", "base": { "expr": "state", "name": "sort" }, "path": "key" }
          ]
        },
        "onSuccess": [
          { "do": "set", "target": "users", "value": { "expr": "get", "base": { "expr": "var", "name": "response" }, "path": "data" } },
          { "do": "set", "target": "totalPages", "value": { "expr": "get", "base": { "expr": "var", "name": "response" }, "path": "totalPages" } }
        ]
      }]
    }
  ]
}

Styling

CSS classes:

  • .data-table - Main container
  • .data-table-header - Header row
  • .data-table-th - Header cell
  • .data-table-th--sortable - Sortable header
  • .data-table-th--sorted - Sorted column
  • .data-table-body - Table body
  • .data-table-row - Data row
  • .data-table-row--selected - Selected row
  • .data-table-cell - Data cell
  • .data-table-pagination - Pagination container
  • .data-table-filter - Filter input

Accessibility

  • ARIA table/grid roles
  • Keyboard navigation for sorting
  • Screen reader announcements for sort state
  • Focus management for pagination