ka-table is a powerful, flexible table component for React that provides advanced features including sorting, filtering, grouping, editing, and virtualization. It's designed with a plugin-based architecture that allows extensive customization and extension. This guide walks through implementing advanced table features using ka-table with React, covering complex data manipulation, custom plugins, and enterprise-grade implementations. This is part 9 of a series on using ka-table with React.
Prerequisites
Before you begin, ensure you have:
- Node.js version 16.0 or higher
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) with hooks support
- Advanced understanding of React hooks, context API, and state management
- Familiarity with TypeScript (highly recommended)
- Knowledge of functional programming concepts
Installation
Install ka-table and its dependencies:
npm install ka-table
Or with yarn:
yarn add ka-table
Or with pnpm:
pnpm add ka-table
Your package.json should include:
{
"dependencies": {
"ka-table": "^9.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
ka-table requires minimal setup. Import the necessary components and styles:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'ka-table/style.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
First Example / Basic Usage
Let's create a basic table component. Create src/DataTable.jsx:
// src/DataTable.jsx
import React, { useState } from 'react';
import { Table } from 'ka-table';
import {
DataType,
SortingMode,
FilteringMode,
PagingPosition
} from 'ka-table/enums';
import { kaPropsUtils } from 'ka-table/utils';
function DataTable() {
const [data, setData] = useState([
{ id: 1, name: 'John Doe', age: 28, email: 'john@example.com', department: 'Engineering' },
{ id: 2, name: 'Jane Smith', age: 32, email: 'jane@example.com', department: 'Marketing' },
{ id: 3, name: 'Bob Johnson', age: 45, email: 'bob@example.com', department: 'Sales' },
{ id: 4, name: 'Alice Williams', age: 29, email: 'alice@example.com', department: 'Engineering' }
]);
const columns = [
{ key: 'id', title: 'ID', dataType: DataType.Number, width: 80 },
{ key: 'name', title: 'Name', dataType: DataType.String, width: 200 },
{ key: 'age', title: 'Age', dataType: DataType.Number, width: 100 },
{ key: 'email', title: 'Email', dataType: DataType.String, width: 250 },
{ key: 'department', title: 'Department', dataType: DataType.String, width: 150 }
];
return (
<div style={{ padding: '20px' }}>
<h2>ka-table Data Table</h2>
<Table
columns={columns}
data={data}
rowKeyField="id"
sortingMode={SortingMode.Single}
filteringMode={FilteringMode.HeaderFilter}
paging={{ enabled: true, pageSize: 10 }}
/>
</div>
);
}
export default DataTable;
Understanding the Basics
ka-table uses a plugin-based architecture where:
- columns: Array of column definition objects
- data: Array of row data objects
- rowKeyField: Unique identifier field for rows
- Plugins: Enable features like sorting, filtering, paging, etc.
Key concepts for advanced usage:
- Enums: Use enums for data types, sorting modes, filtering modes
- Plugins: Extend functionality with custom plugins
- Actions: Dispatch actions to modify table state
- Props Utils: Utility functions for working with table props
Here's an example with editing and custom cell rendering:
// src/EditableTable.jsx
import React, { useState } from 'react';
import { Table } from 'ka-table';
import {
DataType,
SortingMode,
FilteringMode,
EditingMode
} from 'ka-table/enums';
function EditableTable() {
const [data, setData] = useState([
{ id: 1, product: 'Laptop', price: 999.99, stock: 15, category: 'Electronics' },
{ id: 2, product: 'Mouse', price: 29.99, stock: 8, category: 'Electronics' },
{ id: 3, product: 'Keyboard', price: 79.99, stock: 12, category: 'Electronics' }
]);
const columns = [
{ key: 'id', title: 'ID', dataType: DataType.Number, width: 80 },
{
key: 'product',
title: 'Product',
dataType: DataType.String,
width: 200,
editor: (props) => (
<input
type="text"
value={props.value}
onChange={(e) => props.onValueChange(e.target.value)}
/>
)
},
{
key: 'price',
title: 'Price',
dataType: DataType.Number,
width: 120,
format: (value) => `$${value.toFixed(2)}`
},
{
key: 'stock',
title: 'Stock',
dataType: DataType.Number,
width: 100,
style: (value) => ({
backgroundColor: value < 10 ? '#ffebee' : 'transparent'
})
},
{ key: 'category', title: 'Category', dataType: DataType.String, width: 150 }
];
return (
<div style={{ padding: '20px' }}>
<h2>Editable Table</h2>
<Table
columns={columns}
data={data}
rowKeyField="id"
editingMode={EditingMode.Cell}
sortingMode={SortingMode.Single}
filteringMode={FilteringMode.HeaderFilter}
/>
</div>
);
}
export default EditableTable;
Practical Example / Building Something Real
Let's build a comprehensive admin dashboard table with advanced features:
// src/AdminDashboard.jsx
import React, { useState, useCallback } from 'react';
import { Table } from 'ka-table';
import {
DataType,
SortingMode,
FilteringMode,
EditingMode,
PagingPosition,
ActionType
} from 'ka-table/enums';
import { kaPropsUtils } from 'ka-table/utils';
function AdminDashboard() {
const [data, setData] = useState([
{
id: 1,
name: 'Sarah Johnson',
email: 'sarah@example.com',
department: 'Engineering',
salary: 95000,
startDate: '2020-01-15',
status: 'Active',
role: 'Senior Developer'
},
{
id: 2,
name: 'Michael Chen',
email: 'michael@example.com',
department: 'Marketing',
salary: 75000,
startDate: '2019-06-20',
status: 'Active',
role: 'Marketing Manager'
},
{
id: 3,
name: 'Emily Davis',
email: 'emily@example.com',
department: 'Sales',
salary: 65000,
startDate: '2021-03-10',
status: 'Active',
role: 'Sales Representative'
},
{
id: 4,
name: 'David Wilson',
email: 'david@example.com',
department: 'Engineering',
salary: 110000,
startDate: '2018-09-05',
status: 'Active',
role: 'Tech Lead'
}
]);
const [tableProps, changeTableProps] = useState({
columns: [
{
key: 'id',
title: 'ID',
dataType: DataType.Number,
width: 80,
style: { textAlign: 'center' }
},
{
key: 'name',
title: 'Employee Name',
dataType: DataType.String,
width: 200,
filterRowValue: '',
editor: (props) => (
<input
type="text"
value={props.value || ''}
onChange={(e) => props.onValueChange(e.target.value)}
style={{ width: '100%' }}
/>
)
},
{
key: 'email',
title: 'Email',
dataType: DataType.String,
width: 250,
filterRowValue: ''
},
{
key: 'department',
title: 'Department',
dataType: DataType.String,
width: 150,
filterRowValue: '',
editor: (props) => (
<select
value={props.value || ''}
onChange={(e) => props.onValueChange(e.target.value)}
style={{ width: '100%' }}
>
<option value="Engineering">Engineering</option>
<option value="Marketing">Marketing</option>
<option value="Sales">Sales</option>
<option value="HR">HR</option>
</select>
)
},
{
key: 'role',
title: 'Role',
dataType: DataType.String,
width: 180,
filterRowValue: ''
},
{
key: 'salary',
title: 'Salary',
dataType: DataType.Number,
width: 120,
format: (value) => `$${value.toLocaleString()}`,
style: (value) => ({
backgroundColor: value > 100000 ? '#e8f5e9' : 'transparent',
fontWeight: value > 100000 ? 'bold' : 'normal'
}),
editor: (props) => (
<input
type="number"
value={props.value || 0}
onChange={(e) => props.onValueChange(parseFloat(e.target.value) || 0)}
style={{ width: '100%' }}
/>
)
},
{
key: 'startDate',
title: 'Start Date',
dataType: DataType.Date,
width: 120,
format: (value) => {
if (!value) return '';
const date = new Date(value);
return date.toLocaleDateString('en-US');
}
},
{
key: 'status',
title: 'Status',
dataType: DataType.String,
width: 120,
filterRowValue: '',
style: (value) => ({
color: value === 'Active' ? '#28a745' : '#dc3545',
fontWeight: 'bold'
}),
editor: (props) => (
<select
value={props.value || 'Active'}
onChange={(e) => props.onValueChange(e.target.value)}
style={{ width: '100%' }}
>
<option value="Active">Active</option>
<option value="Inactive">Inactive</option>
</select>
)
}
],
data: data,
rowKeyField: 'id',
sortingMode: SortingMode.Single,
filteringMode: FilteringMode.HeaderFilter,
editingMode: EditingMode.Cell,
paging: {
enabled: true,
pageSize: 10,
pageIndex: 0,
position: PagingPosition.Bottom
}
});
const dispatch = useCallback((action) => {
changeTableProps((prevState) => {
switch (action.type) {
case ActionType.UpdateCellValue:
const updatedData = prevState.data.map((row) => {
if (row[prevState.rowKeyField] === action.rowKeyValue) {
return { ...row, [action.columnKey]: action.value };
}
return row;
});
setData(updatedData);
return { ...prevState, data: updatedData };
case ActionType.UpdateFilterRowValue:
return kaPropsUtils.updateFilterRowValue(prevState, action);
case ActionType.UpdateSortDirection:
return kaPropsUtils.updateSortDirection(prevState, action);
case ActionType.UpdatePageIndex:
return kaPropsUtils.updatePageIndex(prevState, action);
default:
return prevState;
}
});
}, []);
const handleAddRow = () => {
const newRow = {
id: Math.max(...data.map(d => d.id)) + 1,
name: 'New Employee',
email: 'new@example.com',
department: 'Engineering',
role: 'Developer',
salary: 50000,
startDate: new Date().toISOString().split('T')[0],
status: 'Active'
};
setData([...data, newRow]);
changeTableProps(prev => ({ ...prev, data: [...data, newRow] }));
};
const handleDeleteRow = () => {
const selectedRows = kaPropsUtils.getSelectedRows(tableProps);
if (selectedRows.length > 0) {
const newData = data.filter(row =>
!selectedRows.some(selected => selected.id === row.id)
);
setData(newData);
changeTableProps(prev => ({ ...prev, data: newData }));
}
};
return (
<div style={{ padding: '20px' }}>
<div style={{ marginBottom: '20px', display: 'flex', gap: '10px', alignItems: 'center' }}>
<h2>Admin Dashboard</h2>
<button
onClick={handleAddRow}
style={{
padding: '8px 16px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Add Row
</button>
<button
onClick={handleDeleteRow}
style={{
padding: '8px 16px',
backgroundColor: '#dc3545',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Delete Selected
</button>
</div>
<Table
{...tableProps}
dispatch={dispatch}
childComponents={{
cell: {
content: (props) => {
if (props.column.key === 'status') {
return (
<span style={{
color: props.value === 'Active' ? '#28a745' : '#dc3545',
fontWeight: 'bold'
}}>
{props.value}
</span>
);
}
return props.value;
}
}
}}
/>
</div>
);
}
export default AdminDashboard;
This advanced example demonstrates:
- Cell editing with custom editors (text input, select dropdown, number input)
- Custom cell rendering with conditional styling
- Filtering with header filters
- Sorting functionality
- Pagination
- Row selection and deletion
- Real-time data updates
- Custom formatting (currency, dates)
- Conditional styling based on cell values
Common Issues / Troubleshooting
Table not rendering: Ensure you've imported the CSS file (
ka-table/style.css). Verify that your data array and columns array are properly structured.Editing not working: Set
editingMode={EditingMode.Cell}and implement custom editors in column definitions. Make sure you're handling the dispatch action forUpdateCellValue.Filtering not working: Enable
filteringMode={FilteringMode.HeaderFilter}and setfilterRowValue: ''in column definitions. Implement theUpdateFilterRowValueaction handler.Sorting not working: Set
sortingMode={SortingMode.Single}orSortingMode.Multipleand implement theUpdateSortDirectionaction handler usingkaPropsUtils.updateSortDirection.Performance issues: For large datasets, ensure virtualization is enabled (default) and consider implementing server-side pagination.
TypeScript errors: Install type definitions if available. ka-table has built-in TypeScript support, so ensure your column and data types match the expected interfaces.
Next Steps
Now that you've mastered ka-table:
- Explore advanced plugins and custom extensions
- Implement server-side data loading and pagination
- Add custom action handlers and event listeners
- Learn about row grouping and aggregation
- Explore custom cell templates and renderers
- Add export functionality (CSV, Excel)
- Check the official repository: https://github.com/komarovalexander/ka-table
- Look for part 10 of this series for more advanced topics
Summary
You've learned how to implement advanced data table features with ka-table, including cell editing, custom rendering, filtering, sorting, and pagination. The plugin-based architecture provides extensive flexibility for building enterprise-grade data management interfaces with excellent performance and customization options.

Top comments (0)