Skip to content

Repository files navigation

@manggala31/react-datatable

Production-ready, keyboard-navigable, server-driven Data Table package for React, Laravel Inertia.js, and Next.js applications.

npm version license


Table of Contents


Overview

@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.


Key Features

  • Keyboard First Navigation: Select and navigate rows effortlessly using J/K or Down/Up arrow keys, and activate rows with Enter.
  • 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.

Installation

# 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-datatable

Quick Start

import 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>
  );
}

Framework Integrations

Laravel Inertia.js (React)

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}
    />
  );
}

API Reference

<DataTable> Props

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).

Keyboard Shortcuts

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)

Styling & Custom Themes

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;
}

License

MIT License © Ilham Hatta Manggala

About

Production-ready, keyboard-navigable, server-driven Data Table package for React, Inertia.js, and Next.js applications.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages