Production-ready, keyboard-navigable, server-driven Data Table package for React, Laravel Inertia.js, and Next.js applications.
- Overview
- Key Features
- Installation
- Quick Start
- Framework Integrations
- API Reference
- Keyboard Shortcuts
- Styling & Custom Themes
- License
@manggala31/react-datatable is a high-performance, keyboard-navigable Data Table component designed for enterprise applications. It bridges server-driven query pipelines (such as Laravel DataTables or custom paginated APIs) with a fluid React frontend UI.
- Keyboard First Navigation: Select and navigate rows effortlessly using
J/KorDown/Uparrow keys, and activate rows withEnter. - Server Driven Pagination: Designed to work seamlessly with paginated API endpoints, query strings, and Inertia.js props.
- Column Customization: Supports column sorting, custom cell renderers, formatting, and alignment controls.
- Bulk Row Selection: Built-in row checkbox selection state management with bulk action handlers.
- Zero Heavy Dependencies: Built with zero external UI framework dependencies.
- Themeable Architecture: Styled via scoped CSS custom properties, fully compatible with Tailwind CSS.
# Using npm
npm install @manggala31/react-datatable
# Using yarn
yarn add @manggala31/react-datatable
# Using pnpm
pnpm add @manggala31/react-datatable
# Using bun
bun add @manggala31/react-datatableimport React, { useState } from 'react';
import { DataTable, Column } from '@manggala31/react-datatable';
import '@manggala31/react-datatable/styles.css';
interface User {
id: number;
name: string;
email: string;
role: string;
status: 'active' | 'inactive';
}
const columns: Column<User>[] = [
{
key: 'id',
title: 'ID',
sortable: true,
width: '80px',
},
{
key: 'name',
title: 'Full Name',
sortable: true,
},
{
key: 'email',
title: 'Email Address',
sortable: true,
},
{
key: 'role',
title: 'Role',
},
{
key: 'status',
title: 'Status',
render: (user) => (
<span className={`status-badge ${user.status}`}>
{user.status.toUpperCase()}
</span>
),
},
];
const mockData: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'active' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'Editor', status: 'active' },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User', status: 'inactive' },
];
export default function UsersTablePage() {
const [selectedRows, setSelectedRows] = useState<User[]>([]);
return (
<div className="container">
<h1>Users Management</h1>
<DataTable<User>
data={mockData}
columns={columns}
rowKey="id"
selectable
onSelectionChange={setSelectedRows}
onRowClick={(row) => console.log('Row clicked:', row)}
/>
</div>
);
}import React from 'react';
import { router } from '@inertiajs/react';
import { DataTable, Column, PaginationMeta } from '@manggala31/react-datatable';
import '@manggala31/react-datatable/styles.css';
interface Props {
users: {
data: any[];
meta: PaginationMeta;
};
}
export default function UsersIndex({ users }: Props) {
const columns: Column<any>[] = [
{ key: 'id', title: 'ID', sortable: true },
{ key: 'name', title: 'Name', sortable: true },
{ key: 'email', title: 'Email', sortable: true },
{ key: 'created_at', title: 'Joined Date' },
];
const handlePageChange = (page: number) => {
router.get(route('users.index'), { page }, { preserveState: true });
};
const handleSortChange = (sortKey: string, direction: 'asc' | 'desc') => {
router.get(route('users.index'), { sort: sortKey, direction }, { preserveState: true });
};
return (
<DataTable
data={users.data}
columns={columns}
rowKey="id"
pagination={users.meta}
onPageChange={handlePageChange}
onSortChange={handleSortChange}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
data |
T[] |
Required | Array of row data items. |
columns |
Column<T>[] |
Required | Column configuration objects array. |
rowKey |
keyof T | ((row: T) => string | number) |
Required | Unique key property or getter for row identification. |
selectable |
boolean |
false |
Enable row checkbox selection column. |
onSelectionChange |
(selectedRows: T[]) => void |
undefined |
Callback invoked when selected rows change. |
onRowClick |
(row: T) => void |
undefined |
Callback fired when a row is clicked or activated via Enter key. |
onPageChange |
(page: number) => void |
undefined |
Callback invoked when pagination page changes. |
onSortChange |
(key: string, direction: 'asc' | 'desc') => void |
undefined |
Callback invoked when column sort changes. |
pagination |
PaginationMeta |
undefined |
Server pagination metadata (total, currentPage, perPage, lastPage). |
| Key | Action |
|---|---|
J / Down Arrow |
Move focus to next row |
K / Up Arrow |
Move focus to previous row |
Space |
Toggle row selection checkbox (when selectable) |
Enter |
Activate selected row (onRowClick) |
Default CSS properties can be customized via CSS custom properties:
:root {
--datatable-bg: #ffffff;
--datatable-border: #e2e8f0;
--datatable-text: #0f172a;
--datatable-muted: #64748b;
--datatable-header-bg: #f8fafc;
--datatable-hover-bg: #f1f5f9;
--datatable-selected-bg: #e0e7ff;
--datatable-primary: #6366f1;
}MIT License © Ilham Hatta Manggala