@mehdashti/tables
v1.2.0
Published
Enterprise-grade data table components for Smart Platform
Downloads
471
Maintainers
Readme
@mehdashti/tables
Enterprise-grade data tables with TanStack Table v8 for Smart Platform.
Features
Core Table Features
- Powerful Sorting: Multi-column sorting with custom sort functions
- Advanced Filtering: Filter Builder with complex AND/OR conditions
- Pagination: Both client-side and server-side pagination support
- Row Selection: Single and multi-row selection with bulk actions
- Column Management: Dynamic show/hide with mobile-responsive defaults
- Type Safe: Full TypeScript support with strict types
- Customizable: Custom cell renderers and formatters
- Loading States: Built-in loading and empty state handling
Enterprise Features (Phase 2)
- Bulk Actions: Toolbar with actions for selected rows (delete, export, archive, etc.)
- Data Export: Export to CSV or Excel with customizable columns
- Aggregations: Summary row with sum, average, min, max calculations
- Inline Editing: Edit cells directly with validation and auto-save
- Row Actions: Edit/Cancel/Save actions for row-level editing
Advanced Features (Phase 5)
- Filter Builder: Visual query builder with multiple operators and conditions
- Filter Chips: Display active filters as removable chips
- Saved Filters: Save and manage filter presets with defaults
- Mobile Card View: Responsive card layout for mobile devices
- Adaptive Columns: Auto-hide columns on mobile with visibility toggle
Installation
pnpm add @mehdashti/tablesUsage
Basic Table
import { DataTable } from '@mehdashti/tables'
import { ColumnDef } from '@tanstack/react-table'
interface User {
id: string
name: string
email: string
role: string
}
const columns: ColumnDef<User>[] = [
{
accessorKey: 'name',
header: 'Name',
},
{
accessorKey: 'email',
header: 'Email',
},
{
accessorKey: 'role',
header: 'Role',
},
]
function UserTable() {
const data: User[] = [
{ id: '1', name: 'John Doe', email: '[email protected]', role: 'Admin' },
{ id: '2', name: 'Jane Smith', email: '[email protected]', role: 'User' },
]
return (
<DataTable
columns={columns}
data={data}
pagination
sorting
/>
)
}With Filtering
<DataTable
columns={columns}
data={data}
filtering
globalFilter
placeholder="Search users..."
/>With Row Selection
function UserTable() {
const [rowSelection, setRowSelection] = useState({})
return (
<DataTable
columns={columns}
data={data}
rowSelection
onRowSelectionChange={setRowSelection}
/>
)
}Server-Side Pagination
function UserTable() {
const [pagination, setPagination] = useState({
pageIndex: 0,
pageSize: 10,
})
const { data, isLoading } = useQuery({
queryKey: ['users', pagination],
queryFn: () => fetchUsers(pagination),
})
return (
<DataTable
columns={columns}
data={data?.items ?? []}
pagination
pageCount={data?.totalPages}
onPaginationChange={setPagination}
isLoading={isLoading}
manualPagination
/>
)
}Column Helpers
Utility functions for common column types:
Sortable Header
import { createSortableHeader } from '@mehdashti/tables'
const columns: ColumnDef<User>[] = [
{
accessorKey: 'name',
header: ({ column }) => createSortableHeader(column, 'Name'),
},
]Selection Column
import { createSelectionColumn } from '@mehdashti/tables'
const columns = [
createSelectionColumn<User>(),
// ... other columns
]Date Column
import { createDateColumn } from '@mehdashti/tables'
const columns = [
createDateColumn<User>('createdAt', 'Created', {
format: 'MMM dd, yyyy',
}),
]Badge Column
import { createBadgeColumn } from '@mehdashti/tables'
const columns = [
createBadgeColumn<User>('status', 'Status', {
active: 'success',
inactive: 'secondary',
pending: 'warning',
}),
]Actions Column
import { createActionsColumn } from '@mehdashti/tables'
const columns = [
createActionsColumn<User>({
onEdit: (user) => console.log('Edit', user),
onDelete: (user) => console.log('Delete', user),
onView: (user) => console.log('View', user),
}),
]API
DataTable Props
interface DataTableProps<TData> {
columns: ColumnDef<TData>[]
data: TData[]
// Features
pagination?: boolean
sorting?: boolean
filtering?: boolean
rowSelection?: boolean
globalFilter?: boolean
// Pagination
pageSize?: number
pageCount?: number
onPaginationChange?: (updater: Updater<PaginationState>) => void
manualPagination?: boolean
// Sorting
onSortingChange?: (updater: Updater<SortingState>) => void
manualSorting?: boolean
// Filtering
onFilteringChange?: (updater: Updater<ColumnFiltersState>) => void
onGlobalFilterChange?: (value: string) => void
manualFiltering?: boolean
// Selection
onRowSelectionChange?: (updater: Updater<RowSelectionState>) => void
// UI
isLoading?: boolean
emptyMessage?: string
placeholder?: string
showColumnVisibility?: boolean
// Styling
className?: string
}Enterprise Features
Bulk Actions
Handle multiple rows with bulk action toolbar.
import { DataTable, BulkActionsToolbar } from '@mehdashti/tables'
function UserTable() {
const [rowSelection, setRowSelection] = useState({})
const handleDelete = (selectedRows: User[]) => {
console.log('Delete', selectedRows)
}
const handleExport = (selectedRows: User[]) => {
console.log('Export', selectedRows)
}
return (
<>
<BulkActionsToolbar
selectedCount={Object.keys(rowSelection).length}
onDelete={handleDelete}
onExport={handleExport}
actions={[
{ label: 'Archive', onClick: handleArchive },
{ label: 'Tag', onClick: handleTag },
]}
/>
<DataTable
columns={columns}
data={data}
rowSelection
onRowSelectionChange={setRowSelection}
/>
</>
)
}Data Export
Export table data to CSV or Excel.
import { ExportButton } from '@mehdashti/tables'
<ExportButton
data={data}
filename="users"
format="csv"
columns={['name', 'email', 'role']}
/>
// Or export to Excel
<ExportButton
data={data}
filename="users"
format="xlsx"
/>Aggregation Row
Show summary calculations at the bottom of the table.
import { AggregationRow } from '@mehdashti/tables'
<AggregationRow
columns={[
{ field: 'revenue', type: 'sum', label: 'Total Revenue' },
{ field: 'orders', type: 'count', label: 'Total Orders' },
{ field: 'rating', type: 'avg', label: 'Avg Rating' },
]}
data={data}
/>Inline Editing
Edit cells directly with validation.
import { EditableCell, RowEditActions } from '@mehdashti/tables'
const columns = [
{
accessorKey: 'name',
header: 'Name',
cell: ({ row, getValue }) => (
<EditableCell
value={getValue()}
onSave={(value) => handleSave(row.id, 'name', value)}
isEditing={row.getIsEditing()}
/>
),
},
{
id: 'actions',
cell: ({ row }) => (
<RowEditActions
isEditing={row.getIsEditing()}
onEdit={() => row.toggleEditing()}
onSave={() => handleRowSave(row)}
onCancel={() => row.toggleEditing()}
/>
),
},
]Advanced Features
Filter Builder
Build complex filter queries with AND/OR logic.
import { FilterBuilder, type FilterGroup } from '@mehdashti/tables'
function TableWithFilters() {
const [filter, setFilter] = useState<FilterGroup>({
id: '1',
logic: 'AND',
conditions: [],
})
return (
<FilterBuilder
fields={[
{ name: 'name', label: 'Name', type: 'string' },
{ name: 'age', label: 'Age', type: 'number' },
{ name: 'status', label: 'Status', type: 'string' },
]}
value={filter}
onChange={setFilter}
/>
)
}Filter Chips
Display and manage active filters.
import { FilterChips } from '@mehdashti/tables'
<FilterChips
filter={currentFilter}
onRemove={(conditionId) => handleRemoveFilter(conditionId)}
onClear={() => setFilter({ id: '1', logic: 'AND', conditions: [] })}
fieldLabels={{
name: 'Full Name',
email: 'Email Address',
status: 'Account Status',
}}
/>Saved Filters
Save and reuse filter presets.
import { SavedFilters, type SavedFilter } from '@mehdashti/tables'
function TableWithSavedFilters() {
const [savedFilters, setSavedFilters] = useState<SavedFilter[]>([])
const [currentFilter, setCurrentFilter] = useState<FilterGroup>(...)
return (
<SavedFilters
filters={savedFilters}
currentFilter={currentFilter}
onApply={(filter) => setCurrentFilter(filter.filter)}
onSave={(name) => {
const newFilter = {
id: generateId(),
name,
filter: currentFilter,
createdAt: new Date(),
}
setSavedFilters([...savedFilters, newFilter])
}}
onDelete={(id) => {
setSavedFilters(savedFilters.filter((f) => f.id !== id))
}}
onSetDefault={(id) => {
setSavedFilters(
savedFilters.map((f) => ({
...f,
isDefault: f.id === id,
}))
)
}}
/>
)
}Mobile Card View
Responsive card layout for mobile devices.
import { MobileCardView, type MobileCardField } from '@mehdashti/tables'
const fields: MobileCardField<User>[] = [
{
accessorKey: 'name',
label: 'Name',
primary: true, // Show as card title
},
{
accessorKey: 'email',
label: 'Email',
},
{
accessorKey: 'role',
label: 'Role',
render: (value) => <Badge>{value}</Badge>,
},
{
accessorKey: 'internalId',
label: 'Internal ID',
hideOnMobile: true, // Hide on mobile
},
]
<MobileCardView
data={users}
fields={fields}
onCardClick={(user) => navigate(`/users/${user.id}`)}
isLoading={isLoading}
emptyMessage="No users found"
/>Column Visibility Toggle
Manage column visibility with mobile defaults.
import { ColumnVisibilityToggle, type ColumnConfig } from '@mehdashti/tables'
const columns: ColumnConfig[] = [
{ id: 'name', label: 'Name', enableHiding: false },
{ id: 'email', label: 'Email' },
{ id: 'phone', label: 'Phone', hideOnMobile: true },
{ id: 'address', label: 'Address', hideOnMobile: true },
{ id: 'status', label: 'Status' },
]
<ColumnVisibilityToggle
columns={columns}
visibility={columnVisibility}
onChange={setColumnVisibility}
/>API Reference
Components
DataTable- Main table component with all featuresBulkActionsToolbar- Toolbar for bulk operationsExportButton- Export data to CSV/ExcelAggregationRow- Summary calculations rowEditableCell- Inline editable cellEditableSelectCell- Inline editable select cellRowEditActions- Edit/Save/Cancel actions for rowsFilterBuilder- Visual query builderFilterChips- Active filter displaySavedFilters- Filter preset managementMobileCardView- Mobile-optimized card layoutColumnVisibilityToggle- Column visibility control
Column Helpers
createSortableHeader- Sortable column headercreateSelectionColumn- Checkbox selection columncreateDateColumn- Formatted date columncreateBadgeColumn- Badge status columncreateActionsColumn- Row actions dropdown
Types
export type FilterOperator =
| "equals" | "notEquals"
| "contains" | "notContains"
| "startsWith" | "endsWith"
| "greaterThan" | "lessThan"
| "greaterThanOrEqual" | "lessThanOrEqual"
| "between" | "in" | "notIn"
| "isEmpty" | "isNotEmpty"
export type FilterCondition = {
id: string
field: string
operator: FilterOperator
value: any
type?: "string" | "number" | "date" | "boolean"
}
export type FilterGroup = {
id: string
logic: "AND" | "OR"
conditions: (FilterCondition | FilterGroup)[]
}
export interface MobileCardField<TData> {
accessorKey: keyof TData
label: string
render?: (value: any, row: TData) => React.ReactNode
primary?: boolean
hideOnMobile?: boolean
}
export interface ColumnConfig {
id: string
label: string
hideOnMobile?: boolean
enableHiding?: boolean
}Examples
See Storybook stories for interactive examples.
License
MIT
