Browse documentation

Build your first table.

v1.1.1

Go from an array of data to a searchable, interactive table. Start with your framework, then add the features your application needs.

Install the package

#

Use an existing TypeScript application with a bundler. Select a framework to see its install command and starter files. The wrappers use the same table engine and options.

Terminal
npm
npm install wts-data-table @wts-data-table/angular

Works with standalone Angular 17–22 applications. The wrapper updates data in place and destroys the table with the component.

Read the complete Angular guide: editing, selection, server data, and lifecycle →

Import the stylesheet once

Add this to your application’s global stylesheet (for example, styles.css or styles.scss). For Next.js, load it from the root layout or global stylesheet.

Global stylesheet
CSS
@import 'wts-data-table/styles.css';

Integrate your framework

#

These two files give you typed columns, stable row IDs, search, selection, and pagination. The same data file works with all four integrations.

1 Define your rows and columns

table-data.ts
TypeScript
import type { DataTableOptions } from 'wts-data-table';

export interface Project {
  id: string;
  name: string;
  status: string;
  budget: number;
}

export const projects: Project[] = [
  { id: 'p1', name: 'Website redesign', status: 'In progress', budget: 24000 },
  { id: 'p2', name: 'Customer portal', status: 'Planning', budget: 18000 },
  { id: 'p3', name: 'Analytics dashboard', status: 'Complete', budget: 32000 }
];

export const columns: DataTableOptions<Project>['columns'] = [
  { accessor: 'name', header: 'Project' },
  { accessor: 'status', header: 'Status', filterVariant: 'select' },
  { accessor: 'budget', header: 'Budget', dataType: 'number' }
];

2 Mount the Angular component

Showing AngularChange framework ↑
project-table.component.ts
TypeScript
import { Component } from '@angular/core';
import {
  WtsDataTableAngularComponent,
  type WtsAngularDataTableOptions
} from '@wts-data-table/angular';
import { columns, projects, type Project } from './table-data';

@Component({
  selector: 'app-project-table',
  standalone: true,
  imports: [WtsDataTableAngularComponent],
  template: `<wts-data-table-angular
    [data]="projects"
    [options]="options"
  />`
})
export class ProjectTableComponent {
  readonly projects = projects;
  readonly options: WtsAngularDataTableOptions<Project> = {
    columns,
    getRowId: row => row.id,
    ariaLabel: 'Project delivery',
    showGlobalFilter: true,
    selectionMode: 'multiple',
    initialState: { pagination: { pageSize: 10 } }
  };
}

Import ProjectTableComponent into its parent component and use <app-project-table /> in the parent template.

Your table is ready to explore.

Try selection, filtering, and card view with editable options and framework code.

Try the example →

Choose a renderer

#

Use Complete for your first integration. Select another renderer when you need precise control over the bundle or your rendered UI.

Base

wts-data-table/base

Tree-shakable renderer where optional behavior is added through exact feature imports.

Lite

wts-data-table/lite

Compact read-heavy renderer with sorting, filtering, paging, grouping, selection, responsive overflow, and virtualization.

Core

wts-data-table/core

DOM-free row model and state engine for applications that own every rendered element.

Example: compose features with Base
Base renderer recipe
TypeScript
import { DataTable } from 'wts-data-table/base';
import { selectionFeature } from 'wts-data-table/features/selection';
import { responsiveFeature } from 'wts-data-table/features/responsive';
import 'wts-data-table/base.css';

new DataTable({
  ...options,
  features: [selectionFeature(), responsiveFeature()]
});

Use your existing options object with a host, data, and columns. See the bundle-size guide for composition choices.

Feature guide

#

Find the option or import for a capability, understand when to use it, and continue to a live example or a focused guide.

39 features

Find and understand data

Turn a large row set into a useful answer.

Sorting

initialState.sorting / setSorting()

Order by one or several typed columns with custom comparators when needed.

Live example

Column filters

columnFilters

Use text, select, boolean, range, date, date-time, and time filters per column.

Live example

Advanced filters

advancedFiltering

Build nested AND/OR rules for complex business queries.

Live example

SearchPanes

searchPanes

Show faceted values and cascading live counts locally or from a server.

Live example

Grouping

showGrouping / state.grouping

Build expandable nested groups from headers or a grouping drop zone.

Live example

Aggregates

aggregation / summaryRows

Calculate count, sum, average, min, max, or custom group and footer totals.

Live example

Pivot models

wts-data-table/pivot

Create DOM-free cross-tab dimensions, values, subtotals, and grand totals.

Section link

Select and change data

Support application workflows without losing stable row identity.

Row selection

selectionMode

Choose none, single, or multiple selection using stable IDs.

Live example

Bulk actions

bulkActions

Act on selected rows or an all-filtered selection without loading every record.

Live example

Cell and range selection

cellSelection

Select cells, rows, columns, and rectangular ranges.

Live example

Inline editing

editing / onEditCommit

Validate and persist keyboard-accessible optimistic edits with rollback.

Live example

AutoFill and paste

autoFill

Copy or continue series across editable ranges and accept TSV input.

Live example

Batch edit history

wts-data-table/edit-history

Validate atomic multi-cell changes and provide bounded undo and redo.

Section link

CRUD editor

wts-data-table/crud

Create, edit, delete, upload, and bulk-edit through several form layouts.

Section link

Tree and detail rows

getSubRows / rowExpansion

Display nested data, lazy children, or master-detail content.

Live example

Ordering and pinning

rowReordering / rowPinning

Move rows with pointer or keyboard and keep important rows visible.

Live example

Control presentation

Adapt the table to product layout, viewport, and export needs.

Column layout

columnMenu / showColumnManager

Resize, reorder, hide, auto-size, and pin columns.

Live example

Responsive details

responsive

Collapse lower-priority columns into accessible inline or popover details.

Live example

Sticky sections

stickyHeader / stickyFooter

Keep multi-row headers and summary footers in view.

Live example

Grouped and temporal columns

headerGroup / filterVariant

Build nested headers and typed date, date-time, and time controls.

Live example

Buttons

buttons

Add copy, CSV, Excel, PDF, print, columns, nested commands, and custom actions.

Live example

Custom content

cell / layout / plugins

Render safe text or DOM nodes and place features into layout slots.

Read guide

Exports

wts-data-table/export

Export to clipboard, CSV, JSON, XLSX, PDF, or semantic print HTML.

Section link

Saved views

wts-data-table/persistence

Store versioned state or encode it into shareable URL parameters.

Section link

Themes and tokens

theme / --wts-table-*

Use framework adapters and 87 supported CSS custom properties.

Read guide

Localization and RTL

wts-data-table/i18n

Load locale packs, negotiate fallback, format values, and apply RTL.

Read guide

Scale and integrate

Choose the data and rendering strategy for the workload.

Adaptive pagination

pagination / pageSizes

Use numbered pages, first/last controls, page jumps, and adaptive ranges.

Live example

Virtualization

virtualization

Mount only visible rows and columns while preserving semantic table markup.

Read guide

Manual server data

manualFiltering / manualSorting / manualPagination

Keep UI state in the table while an API owns querying and row counts.

Read guide

Async data source

wts-data-table/data-source

Add debouncing, cancellation, caching, stale-response protection, and status.

Read guide

Unified server adapter

wts-data-table/server

Share authenticated transports, retries, cache, errors, and telemetry across rows and facets.

Read guide

Database adapters

@wts-data-table/server

Translate allowlisted requests into PostgreSQL, MySQL, SQLite, Knex, or Prisma queries.

Read guide

Cursor and infinite loading

createDataTableCursorDataSourceController()

Append opaque cursor pages from an observer, button, or framework effect.

Read guide

Remote SearchPanes

searchPanes.loadFacets

Load authenticated server facets with cancellation and cascading counts.

Read guide

Transactions

applyTransaction()

Add, update, and remove identified rows without replacing all data.

Read guide

Web Component

wts-data-table/element

Use the complete renderer from standards-based custom elements.

Read guide

Feature plug-ins

wts-data-table/plugin

Install validated behavior with manifests, dependency resolution, and cleanup.

Read guide

Accessibility

ariaLabel / ariaDescription

Use semantic tables, labelled controls, keyboard workflows, and live status.

Live example

Build a production configuration

#

Extend your starter with typed filters, sorting, bulk actions, and a summary. Wrapper components receive the same options without element or data.

Configuration recipe
TypeScript
const table = new DataTable<Project>({
  element: '#project-table',
  ariaLabel: 'Project delivery',
  data: projects,
  getRowId: (row) => row.id,
  columns: [
    { accessor: 'name', header: 'Project', responsive: 'always' },
    { accessor: 'status', header: 'Status', filterVariant: 'select' },
    { accessor: 'budget', header: 'Budget', dataType: 'number', aggregation: 'sum' }
  ],
  initialState: {
    pagination: { pageSize: 25 },
    sorting: [{ id: 'name', direction: 'asc' }]
  },
  showGlobalFilter: true,
  columnFilters: { mode: 'collapsible' },
  columnMenu: true,
  selectionMode: 'multiple',
  bulkActions: true,
  responsive: { breakpoint: 720, details: 'inline' },
  pagination: { mode: 'pages', showPageJump: true },
  summaryRows: { label: 'Total', columns: { budget: 'sum' }, scope: 'filtered' },
  onStateChange: (state, reason) => console.log(reason, state)
});
Choose a data strategy before increasing row counts

Virtualization reduces the rendered DOM. Server processing keeps the full dataset outside browser memory. They solve different problems and can be used together.

Read the server integration guide →

Own state and lifecycle

#

Use the existing controller to change data or view state. These calls are independent examples; replace the application values with your own records.

Controller recipes
TypeScript
const state = table.getState();
const selected = table.getSelectedRows();

table.setGlobalFilter('platform');
table.setSorting([{ id: 'budget', direction: 'desc' }]);
table.setPageSize(50);
table.setData(nextProjects, totalRowCount);
table.applyTransaction({
  add: [newProject],
  update: [{ id: changed.id, data: changed }],
  remove: [deletedId]
});

await table.ready();
await table.destroyAsync();
setColumnFilter()setGrouping()setRowExpanded()pinRow()setColumnVisibility()replaceState()reset()render()
Preserve state across framework renders

Updating data changes rows in place. Replacing the options object remounts the controller. Keep options stable and let the wrapper handle cleanup on unmount.

Understand wrapper lifecycle →
Troubleshooting common integration issues
The table is unstyled
Import the matching stylesheet globally. Complete uses styles.css; Base uses base.css; Lite uses lite.css.
Selection disappears after changing data
Set getRowId to a stable, unique record ID. Avoid array positions as IDs for sortable or changing data.
The table resets on every render
Keep the options object reference stable. In React, create it outside the component or with useMemo.
A detail row repeats the parent data
Use renderDetailPanel for custom details. Real child rows require getSubRows or loadSubRows.

Licensed advanced features

#

Advanced features are included in wts-data-table. Import the feature you need and provide a verified license. Explore a working demonstration before integrating it.

Licensed

Card view

Responsive cards with synchronized search, pagination, and selection. Requires an active subscription with the card-view feature.

wts-data-table/card-viewView demonstration →
Licensed

Advanced row model

Bounded external windows and server-owned row spaces.

wts-data-table/remote · wts-data-table/remote-viewportView demonstration →
Licensed

Background export

Durable asynchronous exports that outlive a browser request.

wts-data-table/export-jobs · wts-data-table/durable-exportView demonstration →
Licensed

Worker processing

Move data processing off the UI thread.

wts-data-table/worker-engine · wts-data-table/worker-tableView demonstration →
Licensed

Live data

Apply ordered real-time changes from WebSocket or custom transports.

wts-data-table/live-data · wts-data-table/live-transportsView demonstration →
Licensed

Server analytics

Build server-backed pivot and analytical queries.

wts-data-table/pivot-controller · wts-data-table/pivot-builderView demonstration →
Licensed

Spreadsheet formulas

Parse, calculate, edit, and project workbook formulas.

wts-data-table/formula-engine · wts-data-table/formula-editorView demonstration →
Licensed

Collaborative editing

Synchronize concurrent editing through application transports.

wts-data-table/collaboration-client · wts-data-table/collaboration-tableView demonstration →
Licensed

Governed editing

Apply review, policy, audit, and controlled-change workflows.

wts-data-table/governance-client · wts-data-table/governance-panelView demonstration →
Licensed

Report designer

Build reusable report definitions and report interfaces.

wts-data-table/report-controller · wts-data-table/report-designerView demonstration →
License verification recipe
TypeScript
import { connectDataTableLicense } from 'wts-data-table/license';
import { createRemoteRowModel } from 'wts-data-table/remote';

const license = await connectDataTableLicense({ licenseKey: deploymentKey });
const rows = createRemoteRowModel({
  license,
  origin: window.location.origin,
  ...options
});

The token and options come from your application. See license integration for feature claims and pricing and licensing to request a quote, access, or renewal.

Developer guides

#

Continue with integration patterns, design choices, and the boundaries your application owns.