On this page
Data Table
A feature-rich data table with sort, multi-sort, column filters, pagination, row selection, row expansion, inline edit, column resize, column visibility, CSV export, and row actions.
uwc-datatable is a full-featured data grid. Pass columns (column definitions)
and data (row array) as properties. It handles sorting, filtering, pagination, row
selection, and more out of the box.
Import
All components
import '@uwc/components';
Selected component (Lit / Angular / Vue)
import { UwcDatatable } from '@uwc/components/datatable';
customElements.define('uwc-datatable', UwcDatatable);
React
import { UwcDatatable } from '@uwc/components/react';
Usage
Lit
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('app-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
columns = [{ field: 'name', header: 'Name' }, { field: 'role', header: 'Role' }];
data = [{ name: 'Alice', role: 'Admin' }, { name: 'Bob', role: 'User' }];
render() {
return html`<uwc-datatable .columns=${this.columns} .data=${this.data}></uwc-datatable>`;
}
}
React
import React from 'react';
import { UwcDatatable } from '@uwc/components/react';
const columns = [{ field: 'name', header: 'Name' }, { field: 'role', header: 'Role' }];
const data = [{ name: 'Alice', role: 'Admin' }, { name: 'Bob', role: 'User' }];
export default function App() {
return <UwcDatatable columns={columns} data={data} />;
}
Angular
import { Component } from '@angular/core';
import '@uwc/datatable';
@Component({
selector: 'app-root',
standalone: true,
template: `<uwc-datatable [columns]="columns" [data]="data"></uwc-datatable>`,
})
export class AppComponent {
columns = [{ field: 'name', header: 'Name' }, { field: 'role', header: 'Role' }];
data = [{ name: 'Alice', role: 'Admin' }, { name: 'Bob', role: 'User' }];
}
Vue
import '@uwc/datatable';
export default {
data() {
return {
columns: [{ field: 'name', header: 'Name' }, { field: 'role', header: 'Role' }],
data: [{ name: 'Alice', role: 'Admin' }, { name: 'Bob', role: 'User' }],
};
},
template: `<uwc-datatable :columns="columns" :data="data"></uwc-datatable>`,
};
Basic Usage
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('datatable-overview-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'email', header: 'Email' },
{ field: 'role', header: 'Role', sortable: true },
];
data = [
{ name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob Smith', email: 'bob@example.com', role: 'Developer' },
{ name: 'Carol White', email: 'carol@example.com', role: 'Designer' },
{ name: 'David Brown', email: 'david@example.com', role: 'Manager' },
{ name: 'Eve Davis', email: 'eve@example.com', role: 'Developer' },
];
render() {
return html`
<uwc-datatable .columns=${this.columns} .data=${this.data} paginator rows="3"></uwc-datatable>
`;
}
}
import React from 'react';
import { UwcDatatable } from '@uwc/components/react';
const columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'email', header: 'Email' },
{ field: 'role', header: 'Role', sortable: true },
];
const data = [
{ name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob Smith', email: 'bob@example.com', role: 'Developer' },
{ name: 'Carol White', email: 'carol@example.com', role: 'Designer' },
{ name: 'David Brown', email: 'david@example.com', role: 'Manager' },
{ name: 'Eve Davis', email: 'eve@example.com', role: 'Developer' },
];
export default function App() {
return <UwcDatatable columns={columns} data={data} paginator rows={3} />;
}
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<uwc-datatable [columns]="columns" [data]="data" paginator [rows]="3"></uwc-datatable>
`
})
export class AppComponent {
columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'email', header: 'Email' },
{ field: 'role', header: 'Role', sortable: true },
];
data = [
{ name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob Smith', email: 'bob@example.com', role: 'Developer' },
{ name: 'Carol White', email: 'carol@example.com', role: 'Designer' },
];
}
export default {
data() {
return {
columns: [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'email', header: 'Email' },
{ field: 'role', header: 'Role', sortable: true },
],
data: [
{ name: 'Alice Johnson', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob Smith', email: 'bob@example.com', role: 'Developer' },
{ name: 'Carol White', email: 'carol@example.com', role: 'Designer' },
],
};
},
template: `
<uwc-datatable :columns="columns" :data="data" paginator :rows="3"></uwc-datatable>
`
};
Simple Data Table
Pass columns and data as properties. Add sortable: true to column
definitions to enable column sorting. Use paginator and rows to activate the
built-in pager.
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('datatable-simple-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'country', header: 'Country', sortable: true },
{ field: 'company', header: 'Company' },
{ field: 'status', header: 'Status' },
];
data = [
{ name: 'Alice Johnson', country: 'USA', company: 'Acme Corp', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', company: 'Globex Inc', status: 'Inactive' },
{ name: 'Carol White', country: 'Canada', company: 'Initech', status: 'Active' },
{ name: 'David Brown', country: 'Germany', company: 'Umbrella Co', status: 'Pending' },
{ name: 'Eve Davis', country: 'France', company: 'Cyberdyne', status: 'Active' },
];
render() {
return html`
<uwc-datatable .columns=${this.columns} .data=${this.data} paginator rows="4"></uwc-datatable>
`;
}
}
import React from 'react';
import { UwcDatatable } from '@uwc/components/react';
const columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'country', header: 'Country', sortable: true },
{ field: 'company', header: 'Company' },
{ field: 'status', header: 'Status' },
];
const data = [
{ name: 'Alice Johnson', country: 'USA', company: 'Acme Corp', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', company: 'Globex Inc', status: 'Inactive' },
{ name: 'Carol White', country: 'Canada', company: 'Initech', status: 'Active' },
{ name: 'David Brown', country: 'Germany', company: 'Umbrella Co', status: 'Pending' },
];
export default function App() {
return <UwcDatatable columns={columns} data={data} paginator rows={4} />;
}
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<uwc-datatable [columns]="columns" [data]="data" paginator [rows]="4"></uwc-datatable>
`
})
export class AppComponent {
columns = [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'country', header: 'Country', sortable: true },
{ field: 'company', header: 'Company' },
{ field: 'status', header: 'Status' },
];
data = [
{ name: 'Alice Johnson', country: 'USA', company: 'Acme Corp', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', company: 'Globex Inc', status: 'Inactive' },
{ name: 'Carol White', country: 'Canada', company: 'Initech', status: 'Active' },
];
}
export default {
data() {
return {
columns: [
{ field: 'name', header: 'Name', sortable: true },
{ field: 'country', header: 'Country', sortable: true },
{ field: 'company', header: 'Company' },
{ field: 'status', header: 'Status' },
],
data: [
{ name: 'Alice Johnson', country: 'USA', company: 'Acme Corp', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', company: 'Globex Inc', status: 'Inactive' },
{ name: 'Carol White', country: 'Canada', company: 'Initech', status: 'Active' },
],
};
},
template: `
<uwc-datatable :columns="columns" :data="data" paginator :rows="4"></uwc-datatable>
`
};
Row selection
Set selection-mode to "single" or "multiple" to enable row
selection. Pair with data-key (a unique field name) to track identity. The
uwc-selection-change event fires with { selection }.
import { LitElement, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
@customElement('datatable-selection-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
@state() private _selection: any[] = [];
columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'status', header: 'Status' },
];
data = [
{ id: 1, name: 'Alice', role: 'Designer', status: 'Active' },
{ id: 2, name: 'Bob', role: 'Developer', status: 'Active' },
{ id: 3, name: 'Carol', role: 'Manager', status: 'Inactive' },
{ id: 4, name: 'David', role: 'DevOps', status: 'Active' },
];
render() {
return html`
<uwc-datatable
.columns=${this.columns}
.data=${this.data}
selection-mode="multiple"
data-key="id"
@uwc-selection-change=${(e) => { this._selection = e.detail.selection; }}>
</uwc-datatable>
<p style="margin:.75rem 0 0;font-size:.8rem;font-family:monospace;color:#374151;">
Selected: ${this._selection.map(r => r.name).join(', ') || 'none'}
</p>
`;
}
}
import React, { useState } from 'react';
import { UwcDatatable } from '@uwc/components/react';
const columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'status', header: 'Status' },
];
const data = [
{ id: 1, name: 'Alice', role: 'Designer', status: 'Active' },
{ id: 2, name: 'Bob', role: 'Developer', status: 'Active' },
{ id: 3, name: 'Carol', role: 'Manager', status: 'Inactive' },
{ id: 4, name: 'David', role: 'DevOps', status: 'Active' },
];
export default function App() {
const [selection, setSelection] = useState([]);
return (
<>
<UwcDatatable
columns={columns}
data={data}
selectionMode="multiple"
dataKey="id"
onUwcSelectionChange={(e) => setSelection(e.detail.selection)}
/>
<p style={{ marginTop: '.75rem', fontSize: '.8rem', fontFamily: 'monospace', color: '#374151' }}>
Selected: {selection.map(r => r.name).join(', ') || 'none'}
</p>
</>
);
}
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<uwc-datatable
[columns]="columns"
[data]="data"
selection-mode="multiple"
data-key="id"
(uwc-selection-change)="selection.set($event.detail.selection)">
</uwc-datatable>
<p style="margin:.75rem 0 0;font-size:.8rem;font-family:monospace;color:#374151;">
Selected: {{ selectionNames() || 'none' }}
</p>
`
})
export class AppComponent {
readonly selection = signal<any[]>([]);
readonly selectionNames = computed(() => this.selection().map(r => r.name).join(', '));
columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'status', header: 'Status' },
];
data = [
{ id: 1, name: 'Alice', role: 'Designer', status: 'Active' },
{ id: 2, name: 'Bob', role: 'Developer', status: 'Active' },
{ id: 3, name: 'Carol', role: 'Manager', status: 'Inactive' },
{ id: 4, name: 'David', role: 'DevOps', status: 'Active' },
];
}
export default {
data() {
return {
selection: [],
columns: [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'status', header: 'Status' },
],
data: [
{ id: 1, name: 'Alice', role: 'Designer', status: 'Active' },
{ id: 2, name: 'Bob', role: 'Developer', status: 'Active' },
{ id: 3, name: 'Carol', role: 'Manager', status: 'Inactive' },
{ id: 4, name: 'David', role: 'DevOps', status: 'Active' },
],
};
},
computed: {
selectionNames() {
return this.selection.map(r => r.name).join(', ') || 'none';
},
},
template: `
<uwc-datatable
:columns="columns"
:data="data"
selection-mode="multiple"
data-key="id"
@uwc-selection-change="selection = $event.detail.selection">
</uwc-datatable>
<p style="margin:.75rem 0 0;font-size:.8rem;font-family:monospace;color:#374151;">
Selected: {{ selectionNames }}
</p>
`
};
Column filters
Add filter: true to any column definition to render a per-column text filter below the
header. Filtering is case-insensitive and applied client-side.
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('datatable-filter-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
columns = [
{ field: 'name', header: 'Name', sortable: true, filter: true },
{ field: 'country', header: 'Country', sortable: true, filter: true },
{ field: 'role', header: 'Role', sortable: true, filter: true },
{ field: 'status', header: 'Status', filter: true },
];
data = [
{ name: 'Alice Johnson', country: 'USA', role: 'Designer', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', role: 'Developer', status: 'Active' },
{ name: 'Carol White', country: 'Canada', role: 'Manager', status: 'Inactive' },
{ name: 'David Brown', country: 'Germany', role: 'DevOps', status: 'Active' },
{ name: 'Eve Davis', country: 'France', role: 'Designer', status: 'Pending' },
{ name: 'Frank Lee', country: 'USA', role: 'Developer', status: 'Active' },
];
render() {
return html`
<uwc-datatable .columns=${this.columns} .data=${this.data} paginator rows="4"></uwc-datatable>
`;
}
}
import React from 'react';
import { UwcDatatable } from '@uwc/components/react';
const columns = [
{ field: 'name', header: 'Name', sortable: true, filter: true },
{ field: 'country', header: 'Country', sortable: true, filter: true },
{ field: 'role', header: 'Role', sortable: true, filter: true },
{ field: 'status', header: 'Status', filter: true },
];
const data = [
{ name: 'Alice Johnson', country: 'USA', role: 'Designer', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', role: 'Developer', status: 'Active' },
{ name: 'Carol White', country: 'Canada', role: 'Manager', status: 'Inactive' },
{ name: 'David Brown', country: 'Germany', role: 'DevOps', status: 'Active' },
{ name: 'Eve Davis', country: 'France', role: 'Designer', status: 'Pending' },
{ name: 'Frank Lee', country: 'USA', role: 'Developer', status: 'Active' },
];
export default function App() {
return <UwcDatatable columns={columns} data={data} paginator rows={4} />;
}
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<uwc-datatable [columns]="columns" [data]="data" paginator [rows]="4"></uwc-datatable>
`
})
export class AppComponent {
columns = [
{ field: 'name', header: 'Name', sortable: true, filter: true },
{ field: 'country', header: 'Country', sortable: true, filter: true },
{ field: 'role', header: 'Role', sortable: true, filter: true },
{ field: 'status', header: 'Status', filter: true },
];
data = [
{ name: 'Alice Johnson', country: 'USA', role: 'Designer', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', role: 'Developer', status: 'Active' },
{ name: 'Carol White', country: 'Canada', role: 'Manager', status: 'Inactive' },
{ name: 'David Brown', country: 'Germany', role: 'DevOps', status: 'Active' },
{ name: 'Eve Davis', country: 'France', role: 'Designer', status: 'Pending' },
{ name: 'Frank Lee', country: 'USA', role: 'Developer', status: 'Active' },
];
}
export default {
data() {
return {
columns: [
{ field: 'name', header: 'Name', sortable: true, filter: true },
{ field: 'country', header: 'Country', sortable: true, filter: true },
{ field: 'role', header: 'Role', sortable: true, filter: true },
{ field: 'status', header: 'Status', filter: true },
],
data: [
{ name: 'Alice Johnson', country: 'USA', role: 'Designer', status: 'Active' },
{ name: 'Bob Smith', country: 'UK', role: 'Developer', status: 'Active' },
{ name: 'Carol White', country: 'Canada', role: 'Manager', status: 'Inactive' },
{ name: 'David Brown', country: 'Germany', role: 'DevOps', status: 'Active' },
{ name: 'Eve Davis', country: 'France', role: 'Designer', status: 'Pending' },
{ name: 'Frank Lee', country: 'USA', role: 'Developer', status: 'Active' },
],
};
},
template: `
<uwc-datatable :columns="columns" :data="data" paginator :rows="4"></uwc-datatable>
`
};
Loading state
Set loading to show a spinner overlay while data is being fetched asynchronously.
import { LitElement, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
@customElement('datatable-loading-demo')
export class AppDemo extends LitElement {
createRenderRoot() { return this; }
@state() private _loading = false;
@state() private _data: any[] = [];
columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'email', header: 'Email' },
];
async _load() {
this._loading = true;
this._data = [];
await new Promise(r => setTimeout(r, 1500));
this._data = [
{ name: 'Alice Johnson', role: 'Admin', email: 'alice@example.com' },
{ name: 'Bob Smith', role: 'Developer', email: 'bob@example.com' },
{ name: 'Carol White', role: 'Designer', email: 'carol@example.com' },
];
this._loading = false;
}
render() {
return html`
<uwc-button label="Fetch data" @click=${this._load} style="margin-bottom:.75rem;display:block;"></uwc-button>
<uwc-datatable .columns=${this.columns} .data=${this._data} ?loading=${this._loading}></uwc-datatable>
`;
}
}
import React, { useState } from 'react';
import { UwcDatatable, UwcButton } from '@uwc/components/react';
const columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'email', header: 'Email' },
];
export default function App() {
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
async function load() {
setLoading(true);
setData([]);
await new Promise(r => setTimeout(r, 1500));
setData([
{ name: 'Alice Johnson', role: 'Admin', email: 'alice@example.com' },
{ name: 'Bob Smith', role: 'Developer', email: 'bob@example.com' },
{ name: 'Carol White', role: 'Designer', email: 'carol@example.com' },
]);
setLoading(false);
}
return (
<>
<UwcButton label="Fetch data" onUwcClick={load} style={{ marginBottom: '.75rem', display: 'block' }} />
<UwcDatatable columns={columns} data={data} loading={loading} />
</>
);
}
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<uwc-button label="Fetch data" (click)="load()" style="margin-bottom:.75rem;display:block;"></uwc-button>
<uwc-datatable [columns]="columns" [data]="data()" [loading]="loading()"></uwc-datatable>
`
})
export class AppComponent {
readonly loading = signal(false);
readonly data = signal<any[]>([]);
columns = [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'email', header: 'Email' },
];
async load() {
this.loading.set(true);
this.data.set([]);
await new Promise(r => setTimeout(r, 1500));
this.data.set([
{ name: 'Alice Johnson', role: 'Admin', email: 'alice@example.com' },
{ name: 'Bob Smith', role: 'Developer', email: 'bob@example.com' },
{ name: 'Carol White', role: 'Designer', email: 'carol@example.com' },
]);
this.loading.set(false);
}
}
export default {
data() {
return {
loading: false,
data: [],
columns: [
{ field: 'name', header: 'Name' },
{ field: 'role', header: 'Role' },
{ field: 'email', header: 'Email' },
],
};
},
methods: {
async load() {
this.loading = true;
this.data = [];
await new Promise(r => setTimeout(r, 1500));
this.data = [
{ name: 'Alice Johnson', role: 'Admin', email: 'alice@example.com' },
{ name: 'Bob Smith', role: 'Developer', email: 'bob@example.com' },
{ name: 'Carol White', role: 'Designer', email: 'carol@example.com' },
];
this.loading = false;
},
},
template: `
<uwc-button label="Fetch data" @click="load" style="margin-bottom:.75rem;display:block;"></uwc-button>
<uwc-datatable :columns="columns" :data="data" :loading="loading"></uwc-datatable>
`
};
Properties
| Name | Type | Default | Description |
|---|---|---|---|
data |
Record<string, unknown>[] |
[] |
— |
columns |
ColumnDef[] |
[] |
— |
selectionMode |
SelectionMode |
'multiple' |
— |
rowKey |
string |
'id' |
— |
loading |
boolean |
false |
— |
rows |
number |
20 |
— |
rowsPerPageOptions |
number[] |
[10, 20, 50, 100] |
— |
scrollableHeight |
string |
'520px' |
— |
rowExpandable |
boolean |
false |
— |
stripedRows |
boolean |
true |
— |
resizableColumns |
boolean |
true |
— |
stateStorage |
string |
'' |
— |
emptyMessage |
string |
'No records found.' |
— |
_pageSize |
number |
20 |
— |
_colPanelOpen |
boolean |
false |
— |
styles |
array |
[styles] |
— |