@madulinux/react-datatable
Version:
Reusable DataTable component for React with sorting, paging, filter, and export.
604 lines (501 loc) โข 15.5 kB
Markdown
# @madulinux/react-datatable
[](https://www.npmjs.com/package/@madulinux/react-datatable)
[](LICENSE)
[](https://www.typescriptlang.org/)
[](https://reactjs.org/)
Enterprise-grade React components for advanced data tables and select inputs with full TypeScript support, accessibility, and modern UI/UX.
## ๐ Quick Links
- ๐ [Complete Documentation](DOCUMENTATION.md)
- ๐ฝ [Select2 Documentation](SELECT2_DOCUMENTATION.md)
- ๐ [npm Package](https://www.npmjs.com/package/@madulinux/react-datatable)
- ๐ [Report Issues](https://github.com/madulinux/react-datatable/issues)
## โจ Features
### DataTable Component
- โ
**Sorting** - Multi-column with default sort support
- โ
**Pagination** - Customizable with per-page options
- โ
**Search** - Global search functionality
- โ
**Filtering** - Simple & advanced filters with filter builder
- โ
**Row Selection** - Single & multiple with bulk actions
- โ
**Export** - CSV & Excel support
- โ
**Column Management** - Visibility toggle & drag-to-reorder
- โ
**Responsive** - Mobile, tablet, desktop optimized
- โ
**Accessibility** - WCAG compliant, keyboard navigation
- โ
**Error Handling** - Robust error management with retry
- โ
**State Persistence** - Save preferences to localStorage
- โ
**TypeScript** - Full type safety with generics
### Select2 Component
- โ
**Async Data** - Load options from API with pagination
- โ
**Search** - Real-time search with debouncing
- โ
**Multi-Select** - Select multiple items with tags
- โ
**Min Input** - Require minimum characters before fetch
- โ
**Max Selections** - Limit number of selections
- โ
**Select All / Clear All** - Bulk selection actions
- โ
**Error Handling** - Robust error management
- โ
**Keyboard Navigation** - Full keyboard support
- โ
**Accessibility** - Screen reader support, ARIA attributes
- โ
**Custom Rendering** - Customize options and selected display
## ๐ Installation
```bash
npm install @madulinux/react-datatable
```
### Peer Dependencies
```json
{
"react": ">=17.0.0",
"react-dom": ">=17.0.0"
}
```
## ๐ฅ Quick Start
### DataTable - Basic Example
```tsx
import DataTable from '@madulinux/react-datatable';
interface User {
id: number;
name: string;
email: string;
status: 'active' | 'inactive';
}
const columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
{
key: 'status',
label: 'Status',
render: (user) => (
<span className={user.status === 'active' ? 'text-green-600' : 'text-gray-400'}>
{user.status}
</span>
)
}
];
const fetchData = async ({ page, perPage, search, orderBy, orderDir }) => {
const response = await fetch(
`/api/users?page=${page}&perPage=${perPage}&search=${search}`
);
const data = await response.json();
return {
data: data.users,
total: data.total
};
};
function UsersTable() {
return (
<DataTable
columns={columns}
fetchData={fetchData}
defaultPerPage={25}
defaultOrderBy="name"
defaultOrderDir="asc"
/>
);
}
```
### Select2 - Basic Example
```tsx
import { Select2 } from '@madulinux/react-datatable';
interface City {
id: number;
label: string;
}
function CitySelector() {
const [selectedCity, setSelectedCity] = useState<City | null>(null);
const fetchCities = async ({ search, page }) => {
const response = await fetch(
`/api/cities?search=${search}&page=${page}&perPage=20`
);
const data = await response.json();
return {
data: data.cities,
hasMore: data.hasMore
};
};
return (
<Select2
value={selectedCity}
onChange={setSelectedCity}
fetchOptions={fetchCities}
placeholder="Select a city..."
/>
);
}
```
## ๐ Documentation
### Complete Guides
- **[DOCUMENTATION.md](DOCUMENTATION.md)** - Complete documentation for all components
- **[SELECT2_DOCUMENTATION.md](SELECT2_DOCUMENTATION.md)** - Detailed Select2 component guide
### Key Topics
1. **DataTable**
- Column configuration
- Sorting & pagination
- Filtering (simple & advanced)
- Row selection & bulk actions
- Export functionality
- Responsive design
- State persistence
2. **Select2**
- Async data fetching
- Search & debouncing
- Multi-select mode
- Min input & max selections
- Custom rendering
- Error handling
3. **Advanced Features**
- Advanced filter builder
- Column visibility & reordering
- Export to CSV/Excel
- Responsive breakpoints
- Accessibility features
## ๐ฏ Advanced Examples
### DataTable with All Features
```tsx
<DataTable
columns={columns}
fetchData={fetchUsers}
filters={filters}
actions={(user) => (
<div className="flex gap-2">
<button onClick={() => editUser(user)}>Edit</button>
<button onClick={() => deleteUser(user)}>Delete</button>
</div>
)}
selectionConfig={{
enableRowSelection: true,
selectionMode: 'multiple',
bulkActions: [
{
label: 'Delete Selected',
action: async (rows) => await deleteUsers(rows),
variant: 'destructive',
requiresConfirmation: true
}
]
}}
exportConfig={{
enableExport: true,
exportFormats: ['csv', 'excel'],
exportFileName: 'users-export'
}}
responsiveConfig={{
enableResponsive: true,
mobileStackedView: true,
compactMode: true
}}
enableColumnVisibility
enableColumnReordering
enableAdvancedFilters
storageKey="users-table"
/>
```
### Select2 Multi-Select with Max Limit
```tsx
<Select2
isMulti
maxSelections={5}
minInput={2}
value={selectedItems}
onChange={setSelectedItems}
fetchOptions={fetchItems}
onMaxSelectionsReached={() => {
toast.error('Maximum 5 items can be selected');
}}
placeholder="Search items (min 2 characters)..."
renderOption={(item) => (
<div className="flex items-center gap-2">
<img src={item.image} className="w-8 h-8 rounded" />
<span>{item.label}</span>
</div>
)}
/>
```
## ๐จ Styling
This package uses **Tailwind CSS** and **shadcn/ui** components. You can customize styling using:
1. **className props**
```tsx
<DataTable className="bg-white rounded-lg shadow" />
```
2. **Tailwind configuration**
```js
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {...}
}
}
}
}
```
3. **CSS variables**
```css
:root {
--primary: ...;
--muted: ...;
}
```
## โฟ Accessibility
All components are built with accessibility in mind:
- โ
**WCAG 2.1 AA** compliant
- โ
**Keyboard navigation** - Full keyboard support
- โ
**Screen readers** - ARIA attributes and live regions
- โ
**Focus management** - Proper focus handling
- โ
**Color contrast** - Meets contrast requirements
## ๐งช TypeScript Support
Full TypeScript support with generics:
```tsx
interface User {
id: number;
name: string;
email: string;
}
// Type-safe columns
const columns: DataTableColumn<User>[] = [
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' }
];
// Type-safe Select2
<Select2<User>
value={selectedUser}
onChange={setSelectedUser}
fetchOptions={fetchUsers}
/>
```
## ๐ฆ What's Included
- `DataTable` - Main data table component
- `Select2` - Advanced select component
- `DataTablePagination` - Standalone pagination
- `AdvancedFilterValueInput` - Filter input component
- `DataTableUtils` - Utility functions
- Type definitions for all components
## ๐ ๏ธ Troubleshooting
### Common Issues
**Data not loading?**
```tsx
// Ensure fetchData returns correct format
return { data: [...], total: 100 };
```
**TypeScript errors?**
```tsx
// Items must have id and label
interface Item {
id: number;
label: string;
}
```
**Infinite re-renders?**
```tsx
// Memoize fetchData
const fetchData = useCallback(async () => {...}, []);
```
See [DOCUMENTATION.md](DOCUMENTATION.md#troubleshooting) for more solutions.
## ๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
## ๐ Changelog
### v1.0.7 (2024-11-03)
**๐ Critical Bug Fix - Filter Not Triggering Fetch**
- Fixed filter changes not triggering data fetch
- Wrapped `activeFilterValues` in `useMemo` to ensure changes are tracked
- Filter state changes now properly trigger `fetchTableData` re-execution
- Added debug logging to track filter value changes
- Enhanced debug logging:
- `activeFilterValues updated: {...}` - When filter values change
- `Filter changed: [key] [value]` - When user changes filter
- `Fetching data with filters: {...}` - When API is called
**Root Cause:**
`activeFilterValues` was a simple assignment (`externalFilterValues ?? filterValues`), which didn't create a new reference when `filterValues` changed. React's dependency tracking couldn't detect the change, so `fetchTableData` wasn't re-executed.
**Solution:**
```typescript
// Before (broken)
const activeFilterValues = externalFilterValues ?? filterValues;
// After (fixed)
const activeFilterValues = useMemo(() => {
return externalFilterValues ?? filterValues;
}, [externalFilterValues, filterValues]);
```
**Expected Console Logs After Fix:**
```
Filter changed: status active
New filter values: {status: 'active'}
activeFilterValues updated: {status: 'active'} โ NEW
Fetching data with filters: {status: 'active'} โ Now triggers!
```
### v1.0.6 (2024-11-03)
**๐ Critical Bug Fixes**
- Fixed "SelectItem cannot have empty value" error in select/multiselect filters
- Changed placeholder value from `""` to `"__all__"`
- Properly handles undefined/cleared filter values
- Fixed "Multiple React instances" error when using date filter
- Removed DatePicker component that was bundling React
- Replaced with native HTML5 `<input type="date">`
- Date and daterange filters now use native browser date picker
- Removed unused DatePicker import to prevent React bundling issues
**โ ๏ธ Breaking Changes**
- Date filters now use native HTML5 date input instead of custom DatePicker
- DatePicker component is no longer used (prevents React bundling conflicts)
**๐ฆ Migration**
If you're using date filters:
```tsx
// Still works the same way, just uses native date input
{
key: 'createdAt',
label: 'Created Date',
type: 'date',
width: 180
}
```
### v1.0.5 (2024-11-03)
**โจ Major Filter System Improvement**
- Created `DataTableFilterInput` component for proper filter type handling
- Full support for all filter types:
- `select` - Dropdown with options
- `multiselect` - Multiple selection (simplified)
- `text` / `search` - Text input
- `number` - Number input
- `date` - Date picker
- `daterange` - Date range picker (from/to)
- `boolean` - Checkbox
- Enhanced `DataTableFilter` interface:
- `width`: Custom width for filter input
- `fetchOptions`: Async data fetching for select/multiselect
- Filters now properly use their `type` property instead of defaulting to select
- Better responsive sizing for filter inputs
- Improved filter value handling (supports string, number, boolean, undefined)
**๐ฆ Usage Example**
```tsx
<DataTable
columns={columns}
fetchData={fetchData}
filters={[
{
key: 'status',
label: 'Status',
type: 'select',
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' }
],
width: 150
},
{
key: 'search',
label: 'Search',
type: 'text',
placeholder: 'Search products...',
width: 250
},
{
key: 'price',
label: 'Price',
type: 'number',
placeholder: 'Min price',
width: 120
},
{
key: 'createdAt',
label: 'Created Date',
type: 'date',
width: 180
},
{
key: 'featured',
label: 'Featured',
type: 'boolean'
}
]}
/>
```
### v1.0.4 (2024-11-03)
**โจ New Features & Improvements**
- Added `DataTableHeaderConfig` interface for header customization
- `showHeader`: Show/hide table header
- `stickyHeader`: Make header sticky on scroll
- `headerClassName`: Custom className for header
- `headerRowClassName`: Custom className for header row
- `headerHeight`: Custom header height
- Enhanced `DataTableColumn` interface:
- `width`, `minWidth`, `maxWidth`: Proper CSS width support (accepts '200px', '20%', or 200)
- `headerClassName`: Custom className for header cells
- `cellClassName`: Custom className for body cells
- `align`: Text alignment ('left' | 'center' | 'right')
- Fixed width property - now uses inline styles instead of broken Tailwind classes
- Added utility functions: `getColumnStyle()`, `getAlignmentClass()`, `getCSSWidth()`
- Improved responsive table styling with better overflow handling
**๐ Bug Fixes**
- Fixed column width not working (was using invalid `'w-' + col.width` approach)
- Fixed header and cell alignment support
**๐ฆ Usage Example**
```tsx
<DataTable
columns={[
{
key: 'name',
label: 'Name',
width: 200, // or '200px' or '20%'
align: 'left',
headerClassName: 'bg-blue-50',
cellClassName: 'font-medium'
},
{
key: 'price',
label: 'Price',
width: '15%',
align: 'right'
}
]}
headerConfig={{
stickyHeader: true,
headerClassName: 'bg-gray-100'
}}
// ... other props
/>
```
### v1.0.3 (2024-11-02)
**๐ Critical Bug Fix**
- Fixed "Invalid hook call" error from Radix UI components bundling their own React
- Added esbuild alias to ensure React is never bundled from any dependency
- Configured `noExternal` for Radix UI packages to bundle them but use external React
- Package now correctly shares single React instance with host application across all dependencies
**๐ฆ Migration**
If you're upgrading from v1.0.2 or earlier:
1. Update to v1.0.3: `npm install @madulinux/react-datatable@latest`
2. Clear your build cache: `npm run build` or `php artisan view:clear`
3. Restart your dev server
4. Error should be completely resolved
### v1.0.2 (2024-11-02)
**๐ Bug Fixes**
- Fixed "Invalid hook call" error when using package in Laravel Inertia and other React applications
- Removed React from bundled dependencies - now properly uses peer dependencies
- Added `react/jsx-runtime` and `react/jsx-dev-runtime` to external dependencies
- Package now correctly shares React instance with host application
**โ ๏ธ Note:** This version had partial fix. v1.0.3 completes the fix for Radix UI dependencies.
## ๐ License
MIT ยฉ [madulinux](https://github.com/madulinux)
## ๐ค Author
**madulinux**
- GitHub: [@madulinux](https://github.com/madulinux)
- npm: [~madulinux](https://www.npmjs.com/~madulinux)
## ๐ Show Your Support
Give a โญ๏ธ if this project helped you!
**Made with โค๏ธ by madulinux**