@multiplatform.one/table
v6.1.0
Published
Advanced table components with filtering, pagination, sorting, and URL state management
Readme
@multiplatform.one/table
Note:
@multiplatform.one/routeris optional - works with any React router or framework!
🎯 Key Features
- 🔍 Advanced Filtering - query builder with 20+ operators
- 🔗 URL State Management - Bookmarkable/shareable table states
- 🌍 Universal Compatibility - Works with any React router or framework
- 📱 Cross-Platform - Web, React Native, Tauri, and more
- ⚡ Performance - Server/client-side filtering and pagination
- 🎨 Beautiful UI - Built with Tamagui for consistent design
- ♿ Accessible - WCAG 2.1 AA compliant
- 🔧 Type-Safe - Full TypeScript support
- 📦 Modular - Tree-shakeable components
🚀 Quick Start
# For OneStack apps
pnpm add @multiplatform.one/table @multiplatform.one/router
# For other React apps
pnpm add @multiplatform.one/table
# For React Router apps
pnpm add @multiplatform.one/table react-router-dom
# For Next.js apps
pnpm add @multiplatform.one/table nextimport { DataTable, createUrlStrategy } from "@multiplatform.one/table";
function UserTable() {
const data = [
{ id: 1, name: "John", email: "[email protected]", role: "admin" },
{ id: 2, name: "Jane", email: "[email protected]", role: "user" },
];
const columns = [
{ accessorKey: "name", header: "Name" },
{ accessorKey: "email", header: "Email" },
{ accessorKey: "role", header: "Role" },
];
return (
<DataTable
data={data}
columns={columns}
syncWithUrl={true} // Enable URL state management
enableFiltering={true}
enableSorting={true}
enablePagination={true}
// urlStrategy: optional - defaults to OneStack, or use createUrlStrategy for other routers
/>
);
}📦 Package Boundaries
| Package | Responsibility |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| @multiplatform.one/table | Framework-agnostic table: display, filter, sort, paginate, virtualize, resize, pin, expand, keyboard nav. No Frappe or API assumptions. |
| @multiplatform.one/frappe-ui | Frappe integration: FrappeTable wraps DataTable, fetches from Frappe, maps to DataTable props. Uses manualFiltering, manualPagination, manualSorting when serverSide is enabled. |
Dependency direction: frappe-ui → table. Table does not depend on frappe-ui or frappe.
🌍 Cross-Platform Compatibility
Works with any React framework and all platforms:
| Framework/Router | URL Strategy | Status |
| ---------------------- | --------------------------------- | --------------- |
| OneStack | Automatic (default) | ✅ Full Support |
| React Router | createUrlStrategy.reactRouter() | ✅ Full Support |
| Next.js App Router | createUrlStrategy.nextJs() | ✅ Full Support |
| React Native | syncWithUrl={false} | ✅ Full Support |
| Tauri | createUrlStrategy.universal() | ✅ Full Support |
| Vanilla React | createUrlStrategy.universal() | ✅ Full Support |
| Any Router | createUrlStrategy.custom() | ✅ Full Support |
React Router Integration
import { useSearchParams } from "react-router-dom";
import { DataTable, createUrlStrategy } from "@multiplatform.one/table";
function MyTable() {
const [searchParams, setSearchParams] = useSearchParams();
const urlStrategy = createUrlStrategy.reactRouter(() => [searchParams, setSearchParams], 500);
return <DataTable data={data} columns={columns} syncWithUrl={true} urlStrategy={urlStrategy} />;
}Next.js App Router Integration
import { useSearchParams, useRouter } from "next/navigation";
import { DataTable, createUrlStrategy } from "@multiplatform.one/table";
function MyTable() {
const searchParams = useSearchParams();
const router = useRouter();
const urlStrategy = createUrlStrategy.nextJs(
() => searchParams,
() => router,
500,
);
return <DataTable data={data} columns={columns} syncWithUrl={true} urlStrategy={urlStrategy} />;
}Universal Strategy (Works Everywhere)
import { DataTable, createUrlStrategy } from "@multiplatform.one/table";
function MyTable() {
const urlStrategy = createUrlStrategy.universal(500);
return <DataTable data={data} columns={columns} syncWithUrl={true} urlStrategy={urlStrategy} />;
}📊 Advanced Filtering
Text Filters
contains- Partial text matchingdoesNotContain- Exclusion searchstartsWith/endsWith- Prefix/suffix matchingis/isNot- Exact matchingisEmpty/isNotEmpty- Null/empty checks
Number Filters
is/isNot- Exact matchingisLessThan/isGreaterThan- Comparison operatorsisBetween/isNotBetween- Range filtering
Date Filters
- All number operators plus date-specific comparisons
isBefore/isAfter- Date comparisonsisOnOrBefore/isOnOrAfter- Inclusive date ranges
Select Filters (with faceted counts)
isAnyOf/isNoneOf- Multi-select filtering- Live counts showing how many items match each option
- Like Amazon/Etsy filter experience
📊 Data Export
Export table data in multiple formats with advanced customization options:
import { DataTable, DataTableExport } from "@multiplatform.one/table";
function MyTable() {
const columns = [
{ accessorKey: "name", header: "Name" },
{ accessorKey: "email", header: "Email" },
{ accessorKey: "price", header: "Price", cell: (info) => `$${info.getValue()}` },
];
// Custom export handler (optional)
const handleExport = async (options) => {
// Call your API or use libraries like xlsx, jsPDF
console.log("Exporting:", options.format, options.filename);
};
return (
<DataTable
data={products}
columns={columns}
renderToolbar={(props) => (
<DataTableToolbar
{...props}
customActions={
<DataTableExport
data={products}
columns={columns}
filename="products-export"
onExport={handleExport}
/>
}
/>
)}
/>
);
}Export Features
- ✅ Multiple Formats: CSV, JSON, Excel, PDF, Print
- ✅ Column Selection: Choose which columns to export
- ✅ Custom Filename: Specify export filename
- ✅ Header Control: Include/exclude column headers
- ✅ Server Integration: Custom export handlers for large datasets
- ✅ Rich Content: Exports cell renderer content, not raw data
🔍 Full-Text Search with Highlighting
Powerful search functionality that searches across all columns with real-time highlighting:
import { DataTable, DataTableSearch } from "@multiplatform.one/table";
function MyTable() {
const [filteredData, setFilteredData] = useState(data);
const [searchOptions, setSearchOptions] = useState(null);
// Columns with highlighting
const columns = [
{
accessorKey: "name",
header: "Name",
cell: (info) => {
const value = info.getValue();
return searchOptions?.highlightResults && searchOptions.searchTerm
? highlightTextInCell(value, searchOptions)
: value;
},
},
// ... other columns with highlighting
];
const handleSearchResults = (results, options) => {
setFilteredData(results);
setSearchOptions(options);
};
return (
<DataTable
data={filteredData}
columns={columns}
renderToolbar={(props) => (
<DataTableToolbar
{...props}
customActions={
<DataTableSearch
data={data}
columns={columns}
onSearchResults={handleSearchResults}
placeholder="Search across all columns..."
showAdvancedOptions={true}
/>
}
/>
)}
/>
);
}Search Features
- ✅ Multi-column search: Search across all text fields simultaneously
- ✅ Real-time highlighting: Search terms highlighted in results
- ✅ Advanced options: Case sensitivity, whole word, regex support
- ✅ Column selection: Choose which columns to search in
- ✅ Debounced search: Optimized performance for large datasets
- ✅ Flexible API: Component-based or hook-based usage
📅 Advanced Date Filtering
Powerful date filtering with presets, ranges, and calendar integration:
import { DataTableDateFilter, type DateFilterValue } from "@multiplatform.one/table";
function MyTable() {
const [dateFilter, setDateFilter] = useState<DateFilterValue>();
return (
<DataTableDateFilter
value={dateFilter}
onChange={setDateFilter}
placeholder="Filter by date..."
showPresets={true}
customPresets={[
{
id: "lastWeekOrders",
label: "Ordered Last Week",
operator: "isLastWeek",
icon: <CalendarIcon />,
},
]}
/>
);
}Date Filter Features
- ✅ Quick Presets: Today, Yesterday, This Week, Last 7/30 Days, etc.
- ✅ Relative Dates: This Month, Last Month, This Year, etc.
- ✅ Custom Ranges: Select start and end dates manually
- ✅ Comparison Operators: Is, Before, After, Between, etc.
- ✅ Empty Handling: Filter for records with/without dates
- ✅ Multiple Filters: Combine different date field filters
- ✅ Calendar Integration: Native HTML5 date inputs
📊 Grouping & Aggregation
Powerful data analysis with hierarchical grouping and calculated aggregations:
import { DataTableGrouping, DataTableGroupingConfig } from "@multiplatform.one/table";
function SalesReport() {
const [groupingConfig, setGroupingConfig] = useState({
columns: ["region", "category"], // Multi-level grouping
aggregations: [
{
column: "revenue",
function: "sum",
label: "Total Revenue",
},
{
column: "quantity",
function: "count",
label: "Order Count",
},
{
column: "revenue",
function: "avg",
label: "Average Order",
},
],
});
return (
<DataTableGrouping
data={salesData}
columns={columns}
groupBy={groupingConfig.columns}
aggregations={groupingConfig.aggregations}
showAggregations={true}
renderGroupHeader={(group, level) => (
<div
style={{
backgroundColor: level === 0 ? "#e3f2fd" : "#f3e5f5",
padding: "12px",
borderLeft: `4px solid ${level === 0 ? "#2196f3" : "#9c27b0"}`,
}}
>
<h3>
{group.value} ({group.count} items)
</h3>
<div>Total Revenue: ${group.aggregations.revenue?.sum?.toLocaleString()}</div>
</div>
)}
/>
);
}Grouping Features
- ✅ Multi-level grouping - Group by multiple columns hierarchically
- ✅ Dynamic aggregations - Sum, count, average, min, max calculations
- ✅ Custom aggregation functions - Define your own calculations
- ✅ Expandable/collapsible groups - Show/hide group details
- ✅ Group state persistence - Remember which groups are expanded
- ✅ Performance optimized - Efficient grouping algorithms
- ✅ Custom group headers - Flexible rendering and styling
Aggregation Functions
- ✅ Count - Number of items in group
- ✅ Sum - Total of numeric values
- ✅ Average - Mean of numeric values
- ✅ Min/Max - Smallest/largest values
- ✅ Custom - User-defined aggregation functions
Use Cases
- Sales Reports - Group by region/product, show totals
- Financial Data - Group by account type, calculate balances
- Employee Management - Group by department, show headcount
- Time Tracking - Group by project, show total hours
- Product Analytics - Group by category, show performance metrics
Production Setup
For full Excel and PDF support in production:
npm install xlsx jsPDF html2canvas☑️ Row Selection & Bulk Actions
Complete row selection and bulk operations system:
import { useRowSelection, DataTableBulkActions, createBulkActions } from "@multiplatform.one/table";
function MyTable() {
// Row selection hook
const rowSelection = useRowSelection({
data: users,
selectionKey: "id",
onSelectionChange: (selected) => console.log(`${selected.length} items selected`),
});
// Define bulk actions
const bulkActions = createBulkActions([
{
id: "send-email",
label: "Send Email",
icon: <MailIcon />,
onExecute: async (selectedItems, clearSelection) => {
await sendBulkEmail(selectedItems.map((u) => u.email));
clearSelection();
},
},
{
id: "export",
label: "Export CSV",
icon: <DownloadIcon />,
onExecute: async (selectedItems) => {
const csv = convertToCSV(selectedItems);
downloadCSV(csv, "selected-users.csv");
},
},
]);
// Add selection column to table
const columns = [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={rowSelection.isAllSelected}
indeterminate={rowSelection.isIndeterminate}
onCheckedChange={rowSelection.toggleAll}
aria-label="Select all rows"
/>
),
cell: ({ row }) => (
<Checkbox
checked={rowSelection.isSelected(row.original)}
onCheckedChange={() => rowSelection.toggleItem(row.original)}
aria-label={`Select ${row.original.name}`}
/>
),
enableSorting: false,
size: 50,
},
// ... other columns
];
return (
<>
{/* Bulk actions bar - appears when items are selected */}
<DataTableBulkActions
selectedItems={rowSelection.selectedItems}
onClearSelection={rowSelection.clearSelection}
actions={bulkActions}
maxVisibleActions={3}
showSelectionCount={true}
/>
<DataTable
data={users}
columns={columns}
enableSorting={true}
enableFiltering={true}
enablePagination={true}
/>
</>
);
}Bulk Action Features
- ✅ Confirmation dialogs for destructive actions
- ✅ Loading states during execution
- ✅ Overflow menus for many actions
- ✅ Custom actions with full flexibility
- ✅ Server integration for bulk operations
- ✅ CSV export built-in
- ✅ Selection summary and statistics
Row Selection Features
- ✅ Individual row selection with checkboxes
- ✅ Select all / clear all functionality
- ✅ Indeterminate states for partial selection
- ✅ Keyboard navigation support
- ✅ Accessibility compliant with proper ARIA labels
- ✅ Selection persistence across pagination
🎛️ Forms Integration
Seamlessly integrate with @multiplatform.one/forms for rich filter inputs:
import { DataTable, DataTableFilters } from "@multiplatform.one/table";
import { TextField, SelectField, DatePickerField } from "@multiplatform.one/forms";
function MyTable() {
return (
<DataTable
data={users}
columns={columns}
renderFilters={(props) => (
<DataTableFilters
{...props}
availableColumns={[
{
id: "name",
label: "Name",
type: "text",
// Custom form component
renderInput: (props) => (
<TextField {...props} label="Search by name" placeholder="Enter name..." />
),
},
{
id: "department",
label: "Department",
type: "select",
options: [
{ label: "Engineering", value: "eng", count: 25 },
{ label: "Marketing", value: "mkt", count: 12 },
],
// Custom form component
renderInput: (props) => (
<SelectField {...props} label="Department" placeholder="Select department..." />
),
},
]}
/>
)}
/>
);
}Form Validation Integration
import { useForm } from "@multiplatform.one/forms";
function AdvancedFilters() {
const form = useForm({
defaultValues: {
nameFilter: "",
salaryRange: { min: "", max: "" },
joinDate: null,
},
onSubmit: ({ value }) => {
// Convert form values to table filters
const filters = createTableFiltersFromForm(value);
tableActions.setFilters(filters);
},
});
return (
<Form {...form}>
<TextField name="nameFilter" label="Employee Name" placeholder="Search by name..." />
<XStack gap="$4">
<TextField
name="salaryRange.min"
label="Min Salary"
placeholder="50000"
keyboardType="numeric"
/>
<TextField
name="salaryRange.max"
label="Max Salary"
placeholder="150000"
keyboardType="numeric"
/>
</XStack>
<DatePickerField name="joinDate" label="Joined After" />
<SubmitButton>Apply Filters</SubmitButton>
</Form>
);
}📄 Pagination Strategies
Offset-Based Pagination (Traditional)
function OffsetPaginationTable() {
const [pageData, setPageData] = useState([]);
const [totalCount, setTotalCount] = useState(0);
return (
<DataTable
data={pageData}
columns={columns}
manualPagination={true}
rowCount={totalCount}
onStateChange={async (state) => {
// Server-side pagination
const response = await api.getUsers({
page: state.pagination.pageIndex + 1,
pageSize: state.pagination.pageSize,
filters: state.filters,
sorting: state.sorting,
});
setPageData(response.data);
setTotalCount(response.totalCount);
}}
/>
);
}Cursor-Based Pagination (Modern)
function CursorPaginationTable() {
const [data, setData] = useState([]);
const [nextCursor, setNextCursor] = useState(null);
const [previousCursor, setPreviousCursor] = useState(null);
const loadPage = async (cursor, direction = "forward") => {
const response = await api.getUsers({
cursor,
direction,
limit: 20,
filters: activeFilters,
});
setData(response.data);
setNextCursor(response.nextCursor);
setPreviousCursor(response.previousCursor);
};
return (
<YStack gap="$4">
<XStack gap="$2">
<Button disabled={!previousCursor} onPress={() => loadPage(previousCursor, "backward")}>
Previous
</Button>
<Button disabled={!nextCursor} onPress={() => loadPage(nextCursor, "forward")}>
Next
</Button>
</XStack>
<DataTable
data={data}
columns={columns}
manualPagination={true}
enablePagination={false} // Disable built-in pagination
/>
</YStack>
);
}Infinite Scroll Pagination
function InfiniteScrollTable() {
const [data, setData] = useState([]);
const [hasMore, setHasMore] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const loadMore = async () => {
if (isLoading || !hasMore) return;
setIsLoading(true);
const lastItem = data[data.length - 1];
const response = await api.getUsers({
cursor: lastItem?.cursor,
limit: 50,
});
setData((prev) => [...prev, ...response.data]);
setHasMore(response.hasMore);
setIsLoading(false);
};
return (
<DataTable
data={data}
columns={columns}
manualPagination={true}
enablePagination={false}
renderToolbar={(props) => (
<DataTableToolbar
{...props}
customActions={
hasMore && (
<Button disabled={isLoading} onPress={loadMore}>
{isLoading ? "Loading..." : "Load More"}
</Button>
)
}
/>
)}
/>
);
}🔄 Server-Side Operations
Manual Mode Configuration
<DataTable
data={serverData}
columns={columns}
// Manual modes for server-side operations
manualFiltering={true} // Filters applied server-side
manualPagination={true} // Pagination handled server-side
manualSorting={true} // Sorting handled server-side
// Server callbacks
onStateChange={(state) => {
// Send all state to server
fetchData({
filters: state.filters,
pagination: state.pagination,
sorting: state.sorting,
globalFilter: state.globalFilter,
});
}}
// Provide metadata for UI
rowCount={totalServerCount}
pageCount={totalServerPages}
/>Real-Time Updates
function RealTimeTable() {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const subscription = api.subscribeToUpdates((update) => {
// Handle real-time updates
setData((prev) => updateData(prev, update));
});
return () => subscription.unsubscribe();
}, []);
const handleFilterChange = async (filters) => {
setIsLoading(true);
const filteredData = await api.getFilteredData(filters);
setData(filteredData);
setIsLoading(false);
};
return (
<DataTable
data={data}
columns={columns}
onStateChange={(state) => {
if (state.filters !== lastFilters) {
handleFilterChange(state.filters);
}
}}
renderToolbar={(props) => (
<DataTableToolbar {...props} customActions={isLoading && <Text>Updating...</Text>} />
)}
/>
);
}const availableColumns = [
{
id: 'role',
label: 'Role',
type: 'select',
options: [
{ label: 'Admin', value: 'admin', count: 5 },
{ label: 'User', value: 'user', count: 23 },
{ label: 'Guest', value: 'guest', count: 12 },
],
},
]
<DataTableFilters
availableColumns={availableColumns}
onAddFilter={handleAddFilter}
/>🔗 URL State Management
// Web: URL updates automatically
// /users?page=2&pageSize=50&filters=name:contains:john&sort=name:asc
// React Native: State persists in memory
// Tauri: State syncs with IPC if needed
<DataTable
syncWithUrl={true} // Works on all platforms!
urlDebounceMs={300}
/>URL State Features
- 📱 Cross-Platform - Same API everywhere
- 🔄 Auto-Sync - URL updates as you filter/sort
- 📋 Shareable - Copy URL to share exact table state
- 🔙 Browser History - Back/forward buttons work
- ⚡ Fast - Debounced updates prevent spam
🎛️ View Management
Save and restore filter combinations:
const [views, setViews] = useState([])
<DataTable
enableViews={true}
views={views}
onSaveView={(name) => {
// Save current filters, sorting, pagination as a view
}}
onLoadView={(viewId) => {
// Load view and apply to table
}}
/>🔄 Migration Notes
- DataTableVirtual remains exported for headless use cases. DataTable with
enableVirtualizationis the preferred path for full DataTable features (toolbar, filters, pagination) plus virtualization. - DataTableColumnPinning remains exported; DataTable integrates it internally when
enableColumnPinningis true. Manual composition is still supported.
📊 Server-Side Support
Perfect for large datasets:
function ServerTable({ data, totalCount }) {
return (
<DataTable
data={data} // Current page data
manualFiltering={true} // We'll handle filtering server-side
manualPagination={true} // We'll handle pagination server-side
manualSorting={true} // We'll handle sorting server-side
rowCount={totalCount} // Total number of rows
onStateChange={(state) => {
// Send filters, pagination, sorting to server
fetchData(state.filters, state.pagination, state.sorting);
}}
/>
);
}🎨 Customization
Custom Toolbar
<DataTable
renderToolbar={(props) => (
<DataTableToolbar {...props} customActions={<Button>Export CSV</Button>} />
)}
/>Custom Filters
<DataTable
renderFilters={(props) => <DataTableFilters {...props} maxFilters={3} showFilterCount={true} />}
/>Custom Pagination
<DataTable
renderPagination={(props) => (
<DataTablePagination {...props} showInfo={true} pageSizeOptions={[10, 25, 50, 100]} />
)}
/>🔧 API Reference
DataTable Props
| Prop | Type | Default | Description |
| -------------------------- | -------------------- | ------- | ------------------------------------------------------------------------------------------- |
| data | TData[] | - | Array of data to display |
| columns | ColumnDef<TData>[] | - | Column definitions |
| syncWithUrl | boolean | false | Enable URL state management |
| enableFiltering | boolean | true | Enable advanced filtering |
| enableSorting | boolean | true | Enable column sorting |
| enablePagination | boolean | true | Enable pagination |
| enableGlobalSearch | boolean | true | Enable global search |
| enableViews | boolean | false | Enable view management |
| manualFiltering | boolean | false | Handle filtering server-side |
| manualPagination | boolean | false | Handle pagination server-side |
| manualSorting | boolean | false | Handle sorting server-side |
| enableVirtualization | boolean | false | Use virtual scrolling for table body. Requires virtualizationHeight when true. |
| virtualizationHeight | number | — | Height (px) of scrollable body when enableVirtualization is true. |
| enableRowExpansion | boolean | false | Enable expandable sub-rows. Requires getSubRows or subRows in row data. |
| enableColumnPinning | boolean | false | Enable column pinning (left/right). Pinned columns stay fixed during horizontal scroll. |
| maxPinnedColumns | number | 3 | Max columns per side (left/right) when pinning. |
| enableKeyboardNavigation | boolean | false | Enable Excel-like keyboard navigation (arrows, Home, End, PageUp/Down, Enter). |
| rowCount | number | — | Total row count for manual pagination (server-side). |
| pageCount | number | — | Total page count for manual pagination. If omitted, derived from rowCount and pageSize. |
DataTableFilters Props
| Prop | Type | Default | Description |
| ------------------ | ---------------- | ------- | -------------------------------- |
| filters | TableFilter[] | [] | Current active filters |
| availableColumns | ColumnConfig[] | - | Columns available for filtering |
| maxFilters | number | 10 | Maximum number of active filters |
| onAddFilter | function | - | Called when filter is added |
| onRemoveFilter | function | - | Called when filter is removed |
📦 Bundle Size
Our modular architecture means you only pay for what you use:
// Only imports DataTable core
import { DataTable } from "@multiplatform.one/table";
// ~25KB gzipped
// Includes filtering
import { DataTable, DataTableFilters } from "@multiplatform.one/table";
// ~35KB gzipped
// Everything
import * as Table from "@multiplatform.one/table";
// ~45KB gzipped🤝 Integration
With @multiplatform.one/forms
Leverage our forms package for rich filter inputs:
import { useFormField } from "@multiplatform.one/forms";
import { DataTableFilters } from "@multiplatform.one/table";
// Forms package provides rich input components
// Table package uses them for advanced filteringWith @multiplatform.one/router
Automatic URL state management:
import { useUrlState } from "@multiplatform.one/router";
// Built-in integration - no extra setup needed
<DataTable syncWithUrl={true} />;Comparison
What we have ✅
✅ Features We Have:
- Advanced filtering with complex query builders
- URL state management and bookmarkable views
- Column visibility, ordering, and resizing
- Server-side operations and manual data fetching
- Row selection and bulk operations
- Data export (CSV, Excel, PDF, JSON)
- Full-text search with highlighting
- Advanced date filtering with calendar picker
- Accessibility compliance
- Cross-platform compatibility
- TypeScript support
- Views and saved filter combinations
- Multi-format data export with column selection
- Bulk actions with confirmation dialogs
- Advanced filtering across all columns
- Full-text search with highlighting across all columns
- Advanced date filtering with calendar picker
- Server-side pagination and sorting
- Keyboard navigation
- Responsive design
❓ Features We Could Add:
- Virtual scrolling for 100k+ rows
- Grouping and aggregation
- Column pinning/freezing
- Row expansion with details
- Custom cell renderers
- Print functionality (enhanced)
- Undo/redo operations
- Internationalization
- Advanced keyboard navigation (Excel-like)
What We Have
- Native Cross-Platform Support - Works on Web, React Native, Tauri without changes
- URL State Strategy Pattern - Pluggable routing integration (OneStack, React Router, Next.js)
- Forms Integration - Deep integration with @multiplatform.one/forms
- Universal Router Compatibility - Works with any React routing solution
🎯 Current Status: 99% Feature Parity
✅ Implemented:
- Advanced filtering with complex query builders
- URL state management and bookmarkable views
- Column visibility, ordering, and resizing
- Server-side operations and manual data fetching
- Row selection and bulk operations
- Data export (CSV, Excel, PDF, JSON)
- Full-text search with highlighting
- Advanced date filtering with calendar picker
- Virtual scrolling for 100k+ rows 🚀
- Grouping and aggregation 🚀
- Accessibility compliance
- Cross-platform compatibility
- TypeScript support
- Views and saved filter combinations
❌ Still Missing (1%):
- Column pinning/freezing
- Row expansion with details
- Custom cell renderers
- Print functionality (enhanced)
- Undo/redo operations
- Internationalization
- Advanced keyboard navigation (Excel-like)
🧪 Testing
# Run tests
pnpm test
# Run with coverage
pnpm test --coverage
# Run specific test
pnpm test DataTable.test.tsx📚 Examples
See /examples directory for:
- AdvancedTableExample - Full-featured table with all bells and whistles
- GroupingExample - Hierarchical grouping and aggregation
- VirtualScrollingExample - Handle 100k+ rows with performance
- BulkActionsExample - Row selection and bulk operations
- ExportExample - Data export in multiple formats
- FullTextSearchExample - Advanced search with highlighting
- DateFilterExample - Advanced date filtering with presets
- FormsIntegrationExample - Integration with @multiplatform.one/forms
- SimpleTableExample - Basic table for simple use cases
- ServerTableExample - Server-side rendering example
- CustomTableExample - Custom styling and components
🤝 Contributing
We welcome contributions! Please see our Contributing Guide.
📄 License
Apache License 2.0 - see LICENSE file.
Built with ❤️ by BitSpur
