npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@algodomain/smart-datatable

v0.1.13

Published

This guide explains how to use the DataTable component: core concepts, feature set, and real-world examples for client, server, and auto (hybrid) modes. It also covers filtering, sorting, pagination, selection, column management with comprehensive reset f

Readme

@algodomain/smart-datatable

This guide explains how to use the DataTable component: core concepts, feature set, and real-world examples for client, server, and auto (hybrid) modes. It also covers filtering, sorting, pagination, selection, column management with comprehensive reset functionality, localStorage persistence, and backend integration via ORM adapters.


Table of Contents

🆕 What's New

Documentation

Reference


Package Details

Install and Configure

Requirements:

  • React 18+
  • Tailwind CSS 4.x+
  1. Install the package (choose your manager):
pnpm add @algodomain/smart-datatable
# or
npm i @algodomain/smart-datatable
# or
yarn add @algodomain/smart-datatable
  1. Make sure your Tailwind CSS entry file (e.g., src/index.css) sources the DataTable package so Tailwind scans its class names. Add ONE of the following @source lines that exists in your node_modules:
/* Ensure Tailwind scans DataTable package classes */
@source "../node_modules/@algodomain/smart-datatable/dist/index.js";
/* OR */
@source "../node_modules/@algodomain/smart-datatable/dist/index.cjs";

If your index.css uses Tailwind v4 style imports, you might already have:

@import "tailwindcss";
  1. Import the DataTable styles once in your app (e.g., in src/main.tsx or on the page where you use the table):
import "@algodomain/smart-datatable/style.css";
  1. Use the component:
import { DataTable } from "@algodomain/smart-datatable";
import type { ColumnDef, APIConfig } from "@algodomain/smart-datatable";

Basics

  • The DataTable is a React + TypeScript component styled with Tailwind and shadcn/ui.
  • Core component import:
import { DataTable } from "@algodomain/smart-datatable"
import type { ColumnDef } from "@algodomain/smart-datatable"

Defining Columns

Each column describes how a field is rendered, sorted, and filtered.

interface Task {
  id: string
  title: string
  status: "In-Progress" | "Canceled" | "Completed" | "Pending" | "New"
  priority: "High" | "Medium" | "Low"
  estimatedHours: number
  createdAt: Date | string
  assignee: string
}

const columns: ColumnDef<Task>[] = [
  { id: "id", header: "Task ID", accessorKey: "id", width: 100, sortable: true, filterable: true, dataType: "string", filterType: "text" },
  { id: "title", header: "Title", accessorKey: "title", width: 200, sortable: true, filterable: true, dataType: "string", textWrap: true },
  {
    id: "status",
    header: "Status",
    accessorKey: "status",
    width: 120,
    sortable: true,
    filterable: true,
    dataType: "string",
    filterType: "select",
    filterOptions: [
      { label: "New", value: "New" },
      { label: "In-Progress", value: "In-Progress" },
      { label: "Pending", value: "Pending" },
      { label: "Completed", value: "Completed" },
      { label: "Canceled", value: "Canceled" },
    ],
  },
  { id: "estimatedHours", header: "Est. Hours", accessorKey: "estimatedHours", width: 100, sortable: true, filterable: true, dataType: "number", filterType: "number" },
  { id: "createdAt", header: "Created At", accessorKey: "createdAt", width: 180, sortable: true, filterable: true, dataType: "date", filterType: "date" },
]

Notes:

  • dataType improves filtering and sorting behavior.
  • filterType: "select" requires filterOptions.
  • textWrap controls whether cell text wraps within column width.

Modes: Client, Server, Auto

  • Client (in-memory): Use when you already have data on the client, or want to fetch all data once from an API endpoint and handle filtering/sorting/pagination client-side.
  • Server: Data is fetched via an API endpoint; sorting/filtering/pagination are handled server-side.
  • Auto (hybrid): Smart caching; starts server-side and can switch to client when all records are cached.

Client Mode Examples

Client Mode with Data Prop:

<DataTable
  columns={columns}
  data={myTasks} // array of Task
  mode="client"
  // Table identification & persistence
  tableId="tasks-table"
  enablePersistence={true}
  persistFilters={true}
  persistSorting={true}
  persistColumnSettings={true}
  // UX
  enableSelection
  selectionMode="multiple"
  enableFiltering
  enableGlobalSearch
  enableSorting
  enableMultiSort
  enableColumnVisibility
  enableColumnReorder
  enableColumnResize
  enableColumnFreeze
  pageSizeOptions={[5, 10, 20, 50]}
  initialPageSize={10}
  showColumnBorders
  onRowClick={(row) => console.log("Row:", row)}
  onSelectionChange={(rows) => console.log("Selected:", rows)}
/>

Client Mode with API Endpoint:

<DataTable
  columns={columns}
  api={{ endpoint: "http://localhost:7070/task-details" }}
  mode="client"
  // Table identification & persistence
  tableId="api-tasks-table"
  enablePersistence={true}
  persistFilters={true}
  persistSorting={true}
  persistColumnSettings={true}
  // UX
  enableSelection
  selectionMode="multiple"
  enableFiltering
  enableGlobalSearch
  enableSorting
  enableMultiSort
  enableColumnVisibility
  enableColumnReorder
  enableColumnResize
  enableColumnFreeze
  pageSizeOptions={[5, 10, 20, 50]}
  initialPageSize={10}
  showColumnBorders
  onRowClick={(row) => console.log("Row:", row)}
  onSelectionChange={(rows) => console.log("Selected:", rows)}
  onError={(error) => console.error("API Error:", error)}
/>

Client Mode Validation:

  • ✅ Use data prop: All data provided directly
  • ✅ Use api prop: Fetches all data once, then handles everything client-side
  • Error: Cannot use both data and api in client mode - the table will display a validation error

API Response Format for Client Mode: The API endpoint should return either:

  • An array of objects directly: [{...}, {...}]
  • An object with a data property: { data: [{...}, {...}] }

HTTP Method Requirements:

  • Client Mode: Requires GET endpoint (fetches all data once)
  • Server Mode: Requires POST endpoint (sends pagination/filtering requests)
  • Auto Mode: Requires POST endpoint (sends pagination/filtering requests)

API Configuration Options:

interface APIConfig {
  endpoint: string; // Required API endpoint
  accessTokenKey?: string; // localStorage key for access token (default: 'accessToken')
  headers?: Record<string, string>; // Additional custom headers to include in requests
}

API Configuration Examples:

// Simple API endpoint
<DataTable
  columns={columns}
  api={{ endpoint: "/api/data" }}
  mode="client"
/>

// API with authentication
<DataTable
  columns={columns}
  api={{ 
    endpoint: "/api/data",
    accessTokenKey: "myToken",
    headers: { "X-API-Key": "key123" }
  }}
  mode="server"
/>

// API with custom headers only
<DataTable
  columns={columns}
  api={{ 
    endpoint: "/api/data",
    headers: { "X-API-Key": "key123", "X-Client-ID": "client-456" }
  }}
  mode="auto"
/>

Benefits of Client Mode with API Endpoint:

  • 🚀 Single API Call: Fetches all data once, then handles filtering/sorting/pagination client-side
  • Fast Interactions: No network delays for filtering, sorting, or pagination after initial load
  • 💾 Offline Capable: Works offline after initial data fetch
  • 🔄 Consistent UX: Same user experience as traditional client-side tables
  • 📊 Perfect for Medium Datasets: Ideal when you have 100-10,000 records that can fit in memory

Server Mode Example

<DataTable
  columns={columns}
  api={{ endpoint: "http://localhost:7070/task-details" }}
  mode="server"
  backendORM="prisma" // prisma | mongoose | typeorm | custom
  // Table identification & persistence
  tableId="server-tasks-table"
  enablePersistence={true}
  persistFilters={true}
  persistSorting={true}
  persistColumnSettings={true}
  pageSizeOptions={[5, 10, 25, 50]}
  initialPageSize={10}
  enableFiltering
  enableGlobalSearch
  enableSorting
  enableMultiSort
  enableColumnVisibility
  enableColumnReorder
  enableColumnResize
  enableColumnFreeze
  maxHeight="70vh"
  showColumnBorders
  onError={(e) => console.error(e)}
/>

Expected request payload shape (client → server):

{
  "page": 1,
  "pageSize": 25,
  "sort": [
    { "column": "createdAt", "direction": "desc" },
    { "column": "priority", "direction": "asc" }
  ],
  "filters": [
    { "column": "status", "operator": "=", "value": "In-Progress" },
    { "column": "estimatedHours", "operator": ">=", "value": 10 }
  ],
  "logicalOperator": "AND"
}

Expected server response:

{
  "data": [ /* array of rows */ ],
  "totalRecords": 1250,
  "page": 1,
  "pageSize": 25,
  "totalPages": 50
}

Auto (Hybrid) Mode Example

<DataTable
  columns={columns}
  api={{ endpoint: "http://localhost:7070/task-details" }}
  mode="auto"
  // Table identification & persistence
  tableId="auto-tasks-table"
  enablePersistence={true}
  persistFilters={true}
  persistSorting={true}
  persistColumnSettings={true}
  serverPageSize={10}
  pageSizeOptions={[5, 10, 25, 50]}
  initialPageSize={5}
  enableSelection
  selectionMode="multiple"
  enableFiltering
  enableGlobalSearch
  enableSorting
  enableMultiSort
  enableColumnVisibility
  enableColumnReorder
  enableColumnResize
  enableColumnFreeze
  maxHeight="70vh"
  showColumnBorders
/>

Hybrid behavior highlights:

  • Caches fetched server pages; won’t re-fetch pages already cached.
  • If all records become cached, operations switch to client mode automatically.

Filtering

There are two per-column filtering UIs, selected automatically:

  • Select filter (when a column has filterType: "select" with filterOptions).
  • Advanced filter for text/number/date with multiple conditions and logical operators.

Operators by type:

  • String: =, !=, contains, startsWith, endsWith, isEmpty, isNotEmpty
  • Number/Date: all string operators plus >, <, >=, <=, between

Examples:

// Text contains
onFilter({ column: "title", operator: "contains", value: "auth" })

// Number between
onFilter({ column: "estimatedHours", operator: "between", value: [10, 20] })

// Select with multiple values
onFilter({ column: "status", operator: "=", value: ["In-Progress", "Pending"] })

Global Search searches across all visible values.

Clear buttons:

  • “Clear Filters” removes all column filters but preserves sorts.
  • “Clear All” removes both filters and sorts.

Sorting

  • Click a column header menu to toggle sort: asc → desc → none.
  • Multi-sort is supported. The header shows sort order and direction numbers when multiple columns are active.
enableSorting
enableMultiSort

Pagination

  • Built-in controls: rows per page, current page, first/prev/next/last.
  • Text summary reflects total vs filtered counts.

Props:

  • pageSizeOptions (e.g., [10, 20, 50, 100, 500])
  • initialPageSize

Selection

  • Enable with enableSelection.
  • selectionMode: single or multiple.
  • Header checkbox selects/deselects all rows on the current page in multiple mode.
enableSelection
selectionMode="multiple"
onSelectionChange={(rows) => console.log(rows)}

Row Counts

  • Enable with enableRowCounts.
  • Adds a lightweight numbering column so users can reference row positions easily.
  • When combined with row selection, the numbering column appears immediately after the selection column.
  • Works in every mode (client/server/auto) and respects pagination so numbering stays continuous across pages.
<DataTable
  columns={columns}
  data={myTasks}
  enableRowCounts
  enableSelection
/>

Grid View (Card Layout)

The Grid View feature allows you to display table rows as responsive cards, ideal for mobile devices and compact displays. Users can toggle between traditional table view and grid/card view.

Enabling Grid View

To enable grid view, provide both enableGridView={true} and a renderGridItem function:

<DataTable
  columns={columns}
  data={myTasks}
  tableId="tasks-grid-table"
  enableGridView={true}
  renderGridItem={(row) => (
    <div className="p-4 border rounded-lg bg-card hover:shadow-md transition-shadow">
      <div className="flex items-start justify-between mb-2">
        <span className="font-mono text-sm text-muted-foreground">{row.id}</span>
        <Badge>{row.status}</Badge>
      </div>
      <h3 className="font-semibold text-sm mb-2">{row.title}</h3>
      <div className="flex items-center gap-2">
        <span className="text-sm text-muted-foreground">{row.assignee}</span>
      </div>
    </div>
  )}
  enableSelection
  selectionMode="multiple"
  onSelectionChange={(rows) => console.log("Selected:", rows)}
/>

Grid View Features

  • Toggle Button: A Grid/Table toggle button appears in the toolbar when grid view is enabled
  • Responsive Layout: Cards automatically adjust to screen size using CSS Grid with auto-fit
  • Selection Support: Checkbox appears on each card when enableSelection={true} - perfect for compare features
  • Row Click: Clicking a card triggers onRowClick callback
  • Consistent Heights: Cards in the same row maintain equal heights
  • Mobile Default: On mobile devices (< 768px), grid view is automatically selected by default
  • Persistence: View mode preference is saved to localStorage per table (requires tableId)

Grid View Props

| Property | Type | Required | Default | Description | |----------|------|----------|---------|-------------| | enableGridView | boolean | ❌ Optional | false | Enables the grid/table toggle button | | renderGridItem | (row: T) => React.ReactNode | ⚠️ Conditional | - | Custom card renderer function. Required when enableGridView={true} |

renderGridItem Function

The renderGridItem function receives a single row and returns a React element representing the card:

renderGridItem={(row) => (
  // Your custom card design
  <div className="p-4 border rounded-lg">
    <h3>{row.title}</h3>
    <p>{row.description}</p>
  </div>
)}

Note: Selection styling (ring highlight) is automatically applied by the DataTable when a card is selected. You don't need to handle selection styles in your renderGridItem function.

Grid View Behavior

Toolbar Changes in Grid View:

  • ✅ Global search remains visible
  • ✅ Clear Filters / Clear All buttons remain visible
  • ✅ Grid/Table toggle button visible
  • ❌ Columns dropdown (visibility/reorder) is hidden

Selection in Grid View:

  • Checkbox appears in the top-right corner of each card
  • Supports both single (radio) and multiple (checkbox) selection modes
  • Selected cards show a primary ring highlight

Mobile Behavior:

  • Automatically defaults to grid view on screens < 768px
  • View preference is persisted per table in localStorage
  • Users can still toggle to table view if needed

Complete Grid View Example

import { DataTable, type ColumnDef } from "@algodomain/smart-datatable"
import { Badge } from "@/components/ui/badge"

interface Task {
  id: string
  title: string
  status: string
  priority: string
  assignee: string
  estimatedHours: number
}

const columns: ColumnDef<Task>[] = [
  { id: "id", header: "ID", accessorKey: "id" },
  { id: "title", header: "Title", accessorKey: "title" },
  { id: "status", header: "Status", accessorKey: "status" },
  { id: "priority", header: "Priority", accessorKey: "priority" },
  { id: "assignee", header: "Assignee", accessorKey: "assignee" },
  { id: "estimatedHours", header: "Est. Hours", accessorKey: "estimatedHours" },
]

export function TasksPage() {
  return (
    <DataTable
      columns={columns}
      data={tasks}
      tableId="tasks-grid-table"
      
      // Grid View Configuration
      enableGridView={true}
      renderGridItem={(row) => (
        <div className="p-4 border rounded-lg bg-card hover:shadow-md transition-shadow">
          {/* Header */}
          <div className="flex items-start justify-between mb-2">
            <span className="font-mono text-sm text-muted-foreground">{row.id}</span>
            <Badge
              className={
                row.status === "Completed" ? "bg-green-100 text-green-800" :
                row.status === "In-Progress" ? "bg-blue-100 text-blue-800" :
                "bg-yellow-100 text-yellow-800"
              }
            >
              {row.status}
            </Badge>
          </div>
          
          {/* Title */}
          <h3 className="font-semibold text-sm mb-2 line-clamp-2">{row.title}</h3>
          
          {/* Assignee */}
          <div className="flex items-center gap-2 mb-2">
            <div className="w-6 h-6 rounded-full bg-gray-300 flex items-center justify-center text-xs">
              {row.assignee.split(" ").map(n => n[0]).join("")}
            </div>
            <span className="text-sm text-muted-foreground">{row.assignee}</span>
          </div>
          
          {/* Footer */}
          <div className="flex items-center justify-between text-sm">
            <span className={
              row.priority === "High" ? "text-red-600 font-medium" :
              row.priority === "Medium" ? "text-yellow-600 font-medium" :
              "text-green-600 font-medium"
            }>
              {row.priority}
            </span>
            <span className="text-muted-foreground">{row.estimatedHours}h</span>
          </div>
        </div>
      )}
      
      // Other features work in both views
      enableSelection
      selectionMode="multiple"
      enableFiltering
      enableGlobalSearch
      enableSorting
      pageSizeOptions={[6, 12, 24]}
      initialPageSize={6}
      onRowClick={(row) => console.log("Clicked:", row)}
      onSelectionChange={(rows) => console.log("Selected:", rows)}
    />
  )
}

Column Management

  • Visibility toggle in Columns menu.
  • Reorder with up/down controls in Columns menu. State persists via localStorage.
  • Resize by dragging the column border (enable with enableColumnResize).
  • Freeze/unfreeze individual columns (left-side sticky marker) with enableColumnFreeze.
  • Text wrapping toggle per column from the header menu. Persisted via localStorage.
  • 🔄 Reset All Settings - Comprehensive reset button in Column Settings dropdown that:
    • Resets column order to original sequence
    • Shows all hidden columns
    • Resets column widths to defaults
    • Unfreezes all columns
    • Resets text wrapping to column defaults
    • Clears localStorage for fresh start

Props:

enableColumnVisibility
enableColumnReorder
enableColumnResize
enableColumnFreeze

Column width controls in ColumnDef:

width?: number
minWidth?: number // default 80
maxWidth?: number // default 500
resizable?: boolean // default true; set false to disable per-column
textWrap?: boolean // default false

Column Reset Feature

The reset button (🔄) in the Column Settings dropdown provides a comprehensive "factory reset" for all column configurations:

What gets reset:

  • ✅ Column order → Original sequence from columns prop
  • ✅ Column visibility → All columns visible (unless visible: false in definition)
  • ✅ Column widths → Original widths from column definitions
  • ✅ Frozen columns → No frozen columns (unless frozen: true in definition)
  • ✅ Text wrapping → Original wrapping settings from column definitions
  • ✅ localStorage → Completely cleared for fresh start

How to use:

  1. Click "Columns" button in table toolbar
  2. Click the 🔄 icon in the top-right of the dropdown
  3. All settings reset instantly

Perfect for:

  • User training and onboarding
  • Testing and debugging
  • User support scenarios
  • Starting fresh between analysis sessions

Persistence & localStorage

The DataTable automatically persists user settings to localStorage for a seamless experience across page reloads.

Automatic Persistence

By default, the following settings are automatically saved and restored:

  • Column Visibility - Show/hide column states
  • Column Order - Custom column reordering
  • Column Widths - Resized column dimensions
  • Frozen Columns - Column freeze states
  • Text Wrapping - Column text wrapping preferences
  • Filters - Active column filters and global search
  • Sorting - Sort configuration (single or multi-column)
  • Pagination - Current page and page size

Table Identification

Each table needs a unique identifier to prevent localStorage conflicts:

<DataTable
  columns={columns}
  data={data}
  tableId="my-unique-table-id" // Required for persistence
/>

localStorage Key Format:

algodomain-smart-dt-{tableId}-{columnHash}

Example: algodomain-smart-dt-user-table-abc123def456

Persistence Controls

Fine-tune what gets persisted with granular controls:

<DataTable
  columns={columns}
  data={data}
  tableId="my-table"
  enablePersistence={true}           // Master switch (default: true)
  persistFilters={true}              // Persist filters & search (default: true)
  persistSorting={true}              // Persist sort config (default: true)
  persistColumnSettings={true}       // Persist column settings (default: true)
/>

Disabling Persistence

// Disable all persistence
<DataTable
  columns={columns}
  data={data}
  enablePersistence={false}
/>

// Selective persistence
<DataTable
  columns={columns}
  data={data}
  tableId="my-table"
  persistFilters={false}        // Don't persist filters
  persistSorting={false}        // Don't persist sorting
  persistColumnSettings={true}  // But do persist column settings
/>

Multi-Table Applications

When using multiple DataTables in the same application, each needs a unique tableId:

<DataTable
  columns={userColumns}
  data={users}
  tableId="users-table"  // Unique ID
/>

<DataTable
  columns={orderColumns}
  data={orders}
  tableId="orders-table" // Different unique ID
/>

localStorage Management

The DataTable handles localStorage operations with error handling:

  • Automatic cleanup when localStorage is full
  • Graceful fallback if localStorage access fails
  • Cross-tab synchronization for real-time updates
  • Data validation to prevent corruption

Reset and Clear

Use the 🔄 reset button in Column Settings to:

  • Reset all column settings to defaults
  • Clear localStorage data for fresh start
  • Restore original table configuration

Fixed Headers and Table Height

  • Provide maxHeight (e.g., "400px" or "50vh") to enable sticky headers with a scrollable body.
  • Horizontal scroll sync is handled between header and body for a smoother UX.
<DataTable
  columns={columns}
  data={myTasks}
  maxHeight="400px"
/>

Styling

  • Uses Tailwind design tokens bound to CSS variables in your app's index.css (or Tailwind entry).
  • Key visual options:
    • showColumnBorders: dashed/dotted borders for dense data sets
    • headerBackgroundColor: customize header background (non-Tailwind inline color supported) - DEPRECATED: use theme.header.backgroundColor instead
    • className: apply additional Tailwind classes
    • theme: comprehensive theme configuration for custom styling

Basic Styling

<DataTable
  columns={columns}
  data={myTasks}
  showColumnBorders
  headerBackgroundColor="#f8f9fa" // Legacy prop - still works
  className="p-4"
/>

Custom Theme Styling

The new theme prop provides comprehensive styling control with support for both hex codes and Tailwind classes. This powerful system allows you to customize every aspect of the table's appearance while maintaining full backward compatibility.

Basic Theme Example:

<DataTable
  columns={columns}
  data={myTasks}
  theme={{
    header: {
      backgroundColor: '#add8e6', // Light blue header (hex)
      textColor: 'text-gray-900' // Dark text (Tailwind class)
    },
    rows: {
      backgroundColor: '#FFFFC5', // Light yellow rows (hex)
      hoverBackgroundColor: 'hover:bg-blue-50', // Hover effect (Tailwind)
      selectedBackgroundColor: '#e6f3ff' // Selected rows (hex)
    },
    container: {
      borderRadius: 'rounded-lg', // Tailwind class
      boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' // CSS shadow
    }
  }}
/>

Complete Theme Examples

Corporate Theme:

<DataTable
  theme={{
    header: {
      backgroundColor: '#1e40af', // Blue header
      textColor: 'text-white', // White text
      borderColor: 'border-blue-600'
    },
    rows: {
      backgroundColor: '#f8fafc', // Light gray rows
      hoverBackgroundColor: 'hover:bg-blue-50', // Subtle blue hover
      selectedBackgroundColor: '#dbeafe', // Light blue selection
      alternateRowBackgroundColor: '#f1f5f9' // Striped rows
    },
    container: {
      borderStyle: 'border-solid',
      borderColor: 'border-gray-200',
      borderRadius: 'rounded-lg',
      boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1)'
    },
    columns: {
      borderColor: 'border-gray-100',
      separatorColor: '#e5e7eb'
    }
  }}
/>

Modern Dark Theme:

<DataTable
  theme={{
    header: {
      backgroundColor: '#374151', // Dark gray header
      textColor: 'text-white',
      borderColor: 'border-gray-600'
    },
    rows: {
      backgroundColor: '#1f2937', // Dark rows
      hoverBackgroundColor: 'hover:bg-gray-700',
      selectedBackgroundColor: '#4b5563',
      textColor: 'text-gray-100'
    },
    container: {
      backgroundColor: '#111827',
      borderStyle: 'border-solid',
      borderColor: 'border-gray-600',
      borderRadius: 'rounded-xl',
      boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.3)'
    },
    controls: {
      backgroundColor: '#374151',
      textColor: 'text-gray-200',
      buttonBackgroundColor: '#4b5563',
      buttonHoverBackgroundColor: '#6b7280'
    }
  }}
/>

Border Style Examples

No Border (Clean Look):

<DataTable
  theme={{
    container: {
      borderStyle: 'border-none',
      boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' // Add shadow for definition
    }
  }}
/>

Dashed Border:

<DataTable
  theme={{
    container: {
      borderStyle: 'border-dashed',
      borderColor: 'border-blue-300'
    }
  }}
/>

Dotted Border:

<DataTable
  theme={{
    container: {
      borderStyle: 'border-dotted',
      borderColor: 'border-red-400'
    }
  }}
/>

Double Border:

<DataTable
  theme={{
    container: {
      borderStyle: 'border-double',
      borderColor: 'border-purple-500'
    }
  }}
/>

Custom CSS Border:

<DataTable
  theme={{
    container: {
      borderStyle: '3px solid',
      borderColor: '#ff0000'
    }
  }}
/>

Mixed Border Styles:

<DataTable
  theme={{
    container: {
      borderStyle: '2px dashed',
      borderColor: '#10b981', // Green dashed border
      borderRadius: 'rounded-2xl',
      padding: '16px'
    },
    columns: {
      borderStyle: 'border-solid',
      borderColor: 'border-gray-200'
    }
  }}
/>

Advanced Theme Combinations

Minimalist Theme:

<DataTable
  theme={{
    header: {
      backgroundColor: 'bg-transparent',
      textColor: 'text-gray-700',
      borderColor: 'border-transparent'
    },
    rows: {
      backgroundColor: 'bg-transparent',
      hoverBackgroundColor: 'hover:bg-gray-50',
      borderColor: 'border-transparent'
    },
    container: {
      borderStyle: 'border-none',
      backgroundColor: 'bg-transparent'
    }
  }}
/>

High Contrast Theme:

<DataTable
  theme={{
    header: {
      backgroundColor: '#000000',
      textColor: '#ffffff',
      borderColor: '#ffffff'
    },
    rows: {
      backgroundColor: '#ffffff',
      hoverBackgroundColor: '#f0f0f0',
      selectedBackgroundColor: '#e0e0e0',
      textColor: '#000000',
      borderColor: '#000000'
    },
    container: {
      borderStyle: 'border-solid',
      borderColor: '#000000',
      borderRadius: 'rounded-none'
    }
  }}
/>

Theme Configuration Options

interface DataTableTheme {
  header?: {
    backgroundColor?: string; // hex like '#f8f9fa' or Tailwind like 'bg-blue-100'
    textColor?: string; // hex or Tailwind like 'text-gray-900'
    borderColor?: string; // hex or Tailwind like 'border-gray-200'
    borderStyle?: string; // CSS border style like '1px solid'
  };
  rows?: {
    backgroundColor?: string; // default row background
    hoverBackgroundColor?: string; // hover state
    selectedBackgroundColor?: string; // selected row background
    alternateRowBackgroundColor?: string; // for striped tables
    textColor?: string;
    borderColor?: string;
    borderStyle?: string;
  };
  container?: {
    backgroundColor?: string;
    borderColor?: string; // hex like '#ff0000' or Tailwind like 'border-red-500'
    borderStyle?: string; // Tailwind like 'border-dashed', 'border-dotted', 'border-none' or CSS like '1px solid'
    borderRadius?: string; // hex or Tailwind like 'rounded-lg'
    padding?: string; // CSS padding
    boxShadow?: string; // CSS shadow
  };
  columns?: {
    borderColor?: string;
    borderStyle?: string;
    separatorColor?: string; // for column separators
  };
  controls?: {
    backgroundColor?: string;
    textColor?: string;
    buttonBackgroundColor?: string;
    buttonHoverBackgroundColor?: string;
    borderColor?: string;
  };
}

Theme Best Practices

Color Input Types:

  • Hex Colors: Use for exact color control (#ff0000, #3b82f6)
  • Tailwind Classes: Use for design system consistency (bg-blue-500, text-gray-900)
  • CSS Values: Use for custom properties (rgb(255, 0, 0), rgba(0, 0, 0, 0.5))

Border Style Guidelines:

  • Tailwind Classes: border-none, border-dashed, border-dotted, border-double, border-solid
  • CSS Values: 1px solid, 2px dashed, 3px dotted
  • Mixed Usage: Combine Tailwind for style, hex for color (borderStyle: 'border-dashed' + borderColor: '#ff0000')

Performance Tips:

  • Use Tailwind classes when possible for better CSS optimization
  • Prefer hex colors for brand-specific colors
  • Use CSS values for precise control (shadows, padding, margins)

Accessibility Considerations:

  • Ensure sufficient color contrast ratios (WCAG AA: 4.5:1, AAA: 7:1)
  • Test with dark and light themes
  • Consider color-blind users when choosing color combinations

Troubleshooting Theme Issues

Common Issues and Solutions:

  1. Styles Not Applying:

    // ❌ Wrong - theme structure
    theme={{
      headerBgColor: '#ff0000' // Wrong property name
    }}
       
    // ✅ Correct - use proper structure
    theme={{
      header: {
        backgroundColor: '#ff0000'
      }
    }}
  2. Border Styles Not Working:

    // ❌ Wrong - invalid border style
    theme={{
      container: {
        borderStyle: 'dashed' // Missing 'border-' prefix
      }
    }}
       
    // ✅ Correct - use proper Tailwind class
    theme={{
      container: {
        borderStyle: 'border-dashed'
      }
    }}
  3. Colors Not Showing:

    // ❌ Wrong - invalid color format
    theme={{
      header: {
        backgroundColor: 'blue' // Not a valid CSS color
      }
    }}
       
    // ✅ Correct - use hex or Tailwind
    theme={{
      header: {
        backgroundColor: '#3b82f6' // Hex color
        // OR
        backgroundColor: 'bg-blue-500' // Tailwind class
      }
    }}
  4. Selected Row Colors Not Working:

    // ✅ Ensure selection is enabled
    <DataTable
      enableSelection={true}
      selectionMode="multiple"
      theme={{
        rows: {
          selectedBackgroundColor: '#e6f3ff'
        }
      }}
    />

Backward Compatibility

The new theme system is fully backward compatible:

  • Existing headerBackgroundColor prop continues to work
  • All default styles remain unchanged
  • Theme values override legacy props when both are provided

Migration Guide:

// Old way (still works)
<DataTable
  headerBackgroundColor="#f8f9fa"
/>

// New way (recommended)
<DataTable
  theme={{
    header: {
      backgroundColor: '#f8f9fa'
    }
  }}
/>

// Both together (theme takes precedence)
<DataTable
  headerBackgroundColor="#f8f9fa" // Legacy prop
  theme={{
    header: {
      backgroundColor: '#add8e6' // This will be used
    }
  }}
/>

Backend Integration with ORM Adapters

Use backendORM to shape the POST request payload into the format expected by your backend:

  • custom (default): pass-through { page, pageSize, sort, filters, logicalOperator }.
  • prisma: builds { where, orderBy, skip, take } with proper Prisma query format and global search support.
  • mongoose: builds { filter, sort, skip, limit } with $and/$or chains and regex for text.
  • typeorm: builds { where, order, skip, take } using a neutral, mappable format.

Example (server mode):

<DataTable
  columns={columns}
  api={{ endpoint: "/api/tasks" }}
  mode="server"
  backendORM="mongoose"
  initialPageSize={25}
/>

Server responsibilities:

  • Accept POST requests with the transformed payload.
  • Apply filtering, sorting, and pagination.
  • Return a JSON response matching { data, totalRecords, page, pageSize, totalPages }.

Prisma Backend Setup

For Prisma ORM, your backend should handle the transformed payload:

// Example Prisma backend endpoint
export const searchOrders = async (req, res, next) => {
  try {
    // DataTable sends the complete Prisma query object
    const prismaQuery = req.body; // { where, orderBy, skip, take }

    // Execute the Prisma query
    const result = await prisma.customerOrder.findMany(prismaQuery);

    // Get total count for pagination
    const { where } = prismaQuery;
    const total = await prisma.customerOrder.count({ where });

    // Calculate pagination info
    const skip = prismaQuery.skip || 0;
    const take = prismaQuery.take || 10;
    const page = Math.floor(skip / take) + 1;
    const totalPages = Math.ceil(total / take);

    res.json({
      data: result,
      totalRecords: total,
      page: page,
      pageSize: take,
      totalPages: totalPages
    });
  } catch (error) {
    next(error);
  }
};

Route Setup:

// Detect DataTable requests by Prisma format
router.post('/', (req, res, next) => {
  if (req.body.skip !== undefined || req.body.take !== undefined || 
      req.body.where !== undefined || req.body.orderBy !== undefined) {
    return searchOrders(req, res, next);
  }
  // Handle other POST requests...
});

Error Handling

  • If the server responds with a non-OK status, an error message is shown in-table.
  • Provide onError to handle errors globally (e.g., toast notifications).
onError={(err) => {
  console.error("DataTable error", err)
}}

Performance Tips

  • Prefer server or auto mode for very large datasets.
  • Use filterType: "select" for categorical columns to reduce user input and improve clarity.
  • Provide dataType for accurate operators and comparisons.
  • Consider virtualizing rows for extremely large client datasets (outside this component).

Full Minimal Examples

Client with data prop (minimal):

<DataTable columns={columns} data={myTasks} />

Client with API endpoint (minimal):

<DataTable columns={columns} api={{ endpoint: "/api/tasks" }} mode="client" />

Server (minimal):

<DataTable columns={columns} api={{ endpoint: "/api/tasks" }} mode="server" />

Auto (minimal):

<DataTable columns={columns} api={{ endpoint: "/api/tasks" }} mode="auto" />

Reference

Complete Properties Reference

| Property | Type | Required | Default | Description | Dependencies & Notes | |----------|------|----------|---------|-------------|---------------------| | Data Configuration | | columns | ColumnDef<T>[] | ✅ Required | - | Column definitions for the table | Must be provided | | data | T[] | ⚠️ Conditional | - | Data array for client mode | Required if mode is "client" or undefined (but not with api) | | api | APIConfig | ⚠️ Conditional | - | API configuration for data fetching | Required if mode is "server" or "auto"; optional for mode="client" | | backendORM | "custom" \| "prisma" \| "mongoose" \| "typeorm" | ❌ Optional | "custom" | Backend ORM adapter for request shaping | Only used in server/auto modes | | Table Identification | | tableId | string | ❌ Optional | Auto-generated | Unique identifier for localStorage | Auto-generated from column IDs if not provided | | Pagination | | mode | "client" \| "server" \| "auto" | ❌ Optional | undefined (client) | Data handling mode | Determines which other props are required | | serverPageSize | number | ❌ Optional | 100 | Page size for server requests | Only used in server/auto modes | | pageSizeOptions | number[] | ❌ Optional | [10, 20, 50, 100, 500] | Available page size options | Used for page size selector | | initialPageSize | number | ❌ Optional | First from pageSizeOptions | Initial page size | Must be one of the values in pageSizeOptions | | Selection | | enableSelection | boolean | ❌ Optional | false | Enable row selection | - | | selectionMode | "single" \| "multiple" | ❌ Optional | "single" | Selection behavior | Requires enableSelection={true} | | enableRowCounts | boolean | ❌ Optional | false | Displays a numbering column | Appears before selection column and follows pagination | | onSelectionChange | (rows: T[]) => void | ❌ Optional | - | Selection change callback | Recommended when using selection | | Filtering | | enableFiltering | boolean | ❌ Optional | true | Enable column filtering | - | | enableGlobalSearch | boolean | ❌ Optional | true | Enable global search | - | | savedFilters | SavedFilter[] | ❌ Optional | [] | Pre-defined saved filters | - | | onSaveFilter | (filter: SavedFilter) => void | ❌ Optional | - | Save filter callback | Recommended when using saved filters | | Sorting | | enableSorting | boolean | ❌ Optional | true | Enable column sorting | - | | enableMultiSort | boolean | ❌ Optional | true | Enable multi-column sorting | Requires enableSorting={true} | | Column Management | | enableColumnVisibility | boolean | ❌ Optional | true | Show/hide columns | - | | enableColumnReorder | boolean | ❌ Optional | false | Drag to reorder columns | - | | enableColumnResize | boolean | ❌ Optional | false | Resize columns by dragging | - | | enableColumnFreeze | boolean | ❌ Optional | false | Freeze columns left/right | - | | enableHeaderFreeze | boolean | ❌ Optional | true | Enable sticky headers | - | | Caching | | cacheTimeout | number | ❌ Optional | 300000 (5 min) | Cache timeout in milliseconds | Only used in auto mode | | maxCacheSize | number | ❌ Optional | 1000 | Maximum cached records | Only used in auto mode | | enablePrefetch | boolean | ❌ Optional | false | Prefetch next pages | Only used in auto mode | | Persistence | | enablePersistence | boolean | ❌ Optional | true | Enable localStorage persistence | Master switch for all persistence | | persistFilters | boolean | ❌ Optional | true | Persist filters and search | Requires enablePersistence={true} | | persistSorting | boolean | ❌ Optional | true | Persist sort configuration | Requires enablePersistence={true} | | persistColumnSettings | boolean | ❌ Optional | true | Persist column settings | Requires enablePersistence={true} | | Styling | | className | string | ❌ Optional | - | Additional CSS classes | Applied to table container | | density | "compact" \| "normal" \| "comfortable" | ❌ Optional | "normal" | Row density | Affects row height and spacing | | showColumnBorders | boolean | ❌ Optional | false | Show column borders | - | | maxHeight | string \| number | ❌ Optional | - | Maximum table height | Enables sticky headers automatically | | headerBackgroundColor | string | ❌ Optional | "#f8f9fa" | Header background color | CSS color value | | Grid View | | enableGridView | boolean | ❌ Optional | false | Enable grid/table toggle | Requires renderGridItem to be provided | | renderGridItem | (row: T) => React.ReactNode | ⚠️ Conditional | - | Custom card renderer function | Required when enableGridView={true} | | Events | | onRowClick | (row: T) => void | ❌ Optional | - | Row click handler | - | | onError | (error: Error) => void | ❌ Optional | - | Error handler | Recommended for production |

Property Dependencies & Requirements

Mode-Specific Requirements

Client Mode (mode="client" or undefined):

  • columns (required)
  • data OR api (one required, but not both)
  • ❌ Cannot use both data and api simultaneously

Server Mode (mode="server"):

  • columns (required)
  • api (required)
  • data (not used)

Auto Mode (mode="auto"):

  • columns (required)
  • api (required)
  • data (not used)

Conditional Requirements

Selection Features:

  • selectionMode requires enableSelection={true}
  • onSelectionChange recommended when using selection

Multi-Column Sorting:

  • enableMultiSort requires enableSorting={true}

Persistence Features:

  • persistFilters, persistSorting, persistColumnSettings require enablePersistence={true}

Caching Features (Auto mode only):

  • cacheTimeout, maxCacheSize, enablePrefetch only apply in auto mode

Grid View Features:

  • renderGridItem is required when enableGridView={true}
  • Grid view defaults to active on mobile (< 768px) when enabled
  • View mode preference is persisted per table in localStorage (requires tableId)

Property Conflicts

Mutually Exclusive:

  • data and api cannot both be used in client mode (will show validation error)
  • enablePersistence={false} disables all persistence features regardless of individual persist* settings

Recommended Combinations:

  • Use tableId when enablePersistence={true} for predictable localStorage keys
  • Use onError handler in production applications
  • Use onSelectionChange when enableSelection={true}
  • Use onSaveFilter when providing savedFilters

ColumnDef Properties Reference

| Property | Type | Required | Default | Description | Dependencies & Notes | |----------|------|----------|---------|-------------|---------------------| | Basic Configuration | | id | string | ✅ Required | - | Unique column identifier | Must be unique across all columns | | header | string | ✅ Required | - | Column header text | Displayed in table header | | accessorKey | keyof T | ✅ Required | - | Key to access data from row object | Must match property in data objects | | Customization | | cell | (row: T) => React.ReactNode | ❌ Optional | - | Custom cell renderer | Receives full row object for rendering | | Functionality | | sortable | boolean | ❌ Optional | true | Enable sorting for this column | Requires enableSorting={true} on DataTable | | filterable | boolean | ❌ Optional | true | Enable filtering for this column | Requires enableFiltering={true} on DataTable | | dataType | "string" \| "number" \| "date" \| "boolean" | ❌ Optional | Auto-detected | Data type for filtering/sorting | Used for proper filter operators | | filterType | "text" \| "number" \| "date" \| "select" \| "boolean" | ❌ Optional | Based on dataType | Filter input type | Determines filter UI component | | filterOptions | { label: string; value: unknown }[] | ⚠️ Conditional | - | Options for select filter | Required when filterType="select" | | Sizing | | width | number | ❌ Optional | 150 | Column width in pixels | Used for initial column width | | minWidth | number | ❌ Optional | 80 | Minimum column width | Prevents columns from becoming too narrow | | maxWidth | number | ❌ Optional | 500 | Maximum column width | Prevents columns from becoming too wide | | resizable | boolean | ❌ Optional | true | Allow column resizing | Requires enableColumnResize={true} on DataTable | | Visibility & Layout | | visible | boolean | ❌ Optional | true | Initial column visibility | Can be changed by user if enableColumnVisibility={true} | | frozen | boolean | ❌ Optional | false | Freeze column to left/right | Requires enableColumnFreeze={true} on DataTable | | frozenPosition | "left" \| "right" | ❌ Optional | "left" | Position for frozen columns | Only applies when frozen={true} | | textWrap | boolean | ❌ Optional | false | Enable text wrapping in cells | Controls text overflow behavior |

ColumnDef Dependencies & Requirements

Conditional Requirements

Filter Configuration:

  • filterOptions is required when filterType="select"
  • filterType should match dataType for optimal UX

Sizing Constraints:

  • minWidth should be ≤ widthmaxWidth
  • width should be within reasonable bounds (50-1000px)

Functionality Dependencies:

  • Column sorting requires both sortable={true} and enableSorting={true} on DataTable
  • Column filtering requires both filterable={true} and enableFiltering={true} on DataTable
  • Column resizing requires both resizable={true} and enableColumnResize={true} on DataTable
  • Column freezing requires both frozen={true} and enableColumnFreeze={true} on DataTable

Best Practices

Column IDs:

  • Use descriptive, kebab-case IDs: "user-name", "created-at"
  • Avoid spaces and special characters
  • Keep IDs consistent across different table instances

Data Types:

  • Set dataType explicitly for proper filtering/sorting
  • Use "date" for date columns to enable date picker filters
  • Use "boolean" for true/false columns

Filter Types:

  • Use "select" for columns with limited, known values
  • Use "date" for date columns
  • Use "number" for numeric columns
  • Use "text" for general string columns

Sizing:

  • Set reasonable width values based on content
  • Use minWidth to prevent columns from becoming unusable
  • Use maxWidth to prevent columns from taking too much space

Operators:

type FilterOperator =
  | "=" | "!=" | "contains" | "startsWith" | "endsWith" | "isEmpty" | "isNotEmpty"
  | ">" | "<" | ">=" | "<=" | "between"

Quick Reference & Common Patterns

Minimal Client Table (with data prop)

<DataTable
  columns={columns}
  data={myData}
  tableId="simple-table"
/>

Minimal Client Table (with API endpoint)

<DataTable
  columns={columns}
  api={{ endpoint: "/api/data" }}
  mode="client"
  tableId="api-table"
/>

Full-Featured Client Table

<DataTable
  columns={columns}
  data={myData}
  tableId="full-table"
  enableRowCounts
  enableSelection
  selectionMode="multiple"
  enableFiltering
  enableGlobalSearch
  enableSorting
  enableMultiSort
  enableColumnVisibility
  enableColumnReorder
  enableColumnResize
  enableColumnFreeze
  maxHeight="400px"
  showColumnBorders
  onRowClick={(row) => console.log(row)}
  onSelectionChange={(rows) => console.log(rows)}
/>

Server Table with Persistence

<DataTable
  columns={columns}
  api={{ endpoint: "/api/data" }}
  mode="server"
  tableId="server-table"
  backendORM="prisma"
  enablePersistence={true}
  persistFilters={true}
  persistSorting={true}
  persistColumnSettings={true}
  pageSizeOptions={[10, 25, 50, 100]}
  initialPageSize={25}
/>

Auto Mode with Caching

<DataTable
  columns={columns}
  api={{ endpoint: "/api/data" }}
  mode="auto"
  tableId="auto-table"
  serverPageSize={50}
  enablePrefetch={true}
  cacheTimeout={600000}
  maxCacheSize={2000}
/>

Disable Persistence

<DataTable
  columns={columns}
  data={myData}
  enablePersistence={false}
  // All persistence features disabled
/>

Selective Persistence

<DataTable
  columns={columns}
  data={myData}
  tableId="selective-table"
  persistFilters={false}        // Don't persist filters
  persistSorting={false}        // Don't persist sorting
  persistColumnSettings={true}  // But do persist column settings
/>

Grid View (Card Layout)

<DataTable
  columns={columns}
  data={myData}
  tableId="grid-table"
  enableGridView={true}
  renderGridItem={(row) => (
    <div className="p-4 border rounded-lg">
      <h3 className="font-semibold">{row.title}</h3>
      <p className="text-muted-foreground">{row.description}</p>
    </div>
  )}
  enableSelection
  selectionMode="multiple"
/>

Column Definition Examples

const columns: ColumnDef<Task>[] = [
  // Basic column
  {
    id: "id",
    header: "ID",
    accessorKey: "id",
    width: 80,
  },
  
  // Sortable and filterable column
  {
    id: "title",
    header: "Title",
    accessorKey: "title",
    sortable: true,
    filterable: true,
    dataType: "string",
    filterType: "text",
    width: 200,
  },
  
  // Select filter column
  {
    id: "status",
    header: "Status",
    accessorKey: "status",
    dataType: "string",
    filterType: "select",
    filterOptions: [
      { label: "Active", value: "active" },
      { label: "Inactive", value: "inactive" },
    ],
  },
  
  // Date column with date picker
  {
    id: "createdAt",
    header: "Created At",
    accessorKey: "createdAt",
    dataType: "date",
    filterType: "date",
    width: 150,
  },
  
  // Custom cell renderer
  {
    id: "actions",
    header: "Actions",
    accessorKey: "id",
    cell: (row) => (
      <button onClick={() => handleEdit(row.id)}>
        Edit
      </button>
    ),
    sortable: false,
    filterable: false,
    width: 100,
  },
];

That's it! You're ready to build powerful, user-friendly tables with client, server, or hybrid workflows.

Dynamic Runtime Controls

The DataTable component supports dynamic runtime control of its features. You can create interactive controls that allow users to enable/disable features on-the-fly without any code changes to the DataTable component itself.

Example: Dynamic Feature Controls

import { useState } from 'react'
import { DataTable, type ColumnDef } from "@algodomain/smart-datatable"
import { Checkbox } from "@/components/ui/checkbox"

interface Task {
  id: string
  title: string
  status: string
}

const columns: ColumnDef<Task>[] = [
  { id: "id", header: "ID", accessorKey: "id" },
  { id: "title", header: "Title", accessorKey: "title" },
  { id: "status", header: "Status", accessorKey: "status" },
]

const data: Task[] = [
  { id: "1", title: "Task 1", status: "Active" },
  { id: "2", title: "Task 2", status: "Completed" },
]

export function DynamicControlsExample() {
  // State for dynamic controls
  const [controls, setControls] = useState({
    enableSelection: true,
    enableFiltering: true,
    enableGlobalSearch: true,
    enableSorting: true,
    enableMultiSort: true,
    enableColumnVisibility: true,
    enableColumnReorder: true,
    enableColumnResize: true,
    enableColumnFreeze: true,
    showColumnBorders: true,
  })

  const handleControlChange = (control: string, value: boolean) => {
    setControls(prev => ({ ...prev, [control]: value }))
  }

  return (
    <div className="space-y-4">
      {/* Dynamic Controls */}
      <div className="bg-gray-50 p-4 rounded-lg">
        <h3 className="font-semibold mb-3">Feature Controls</h3>
        <div className="grid grid-cols-2 md:grid-cols-5 gap-4">
          <div className="flex items-center space-x-2">
            <Checkbox
              id="enableSelection"
              checked={controls.enableSelection}
              onCheckedChange={(checked) => handleControlChange('enableSelection', !!checked)}
            />
            <label htmlFor="enableSelection" className="text-sm">Selection</label>
          </div>
          <div className="flex items-center space-x-2">
            <Checkbox
              id="enableFiltering"
              checked={controls.enableFiltering}
              onCheckedChange={(checked) => handleControlChange('enableFiltering', !!checked)}
            />
            <label htmlFor="enableFiltering" className="text-sm">Filtering</label>
          </div>
          <div className="flex items-center space-x-2">
            <Checkbox
              id="enableGlobalSearch"
              checked={controls.enableGlobalSearch}
              onCheckedChange={(checked) => handleControlChange('enableGlobalSearch', !!checked)}
            />
            <label htmlFor="enableGlobalSearch" className="text-sm">Global Search</label>
          </div>
          <div className="flex items-center space-x-2">
            <Checkbox
              id="enableSorting"
              checked={controls.enableSorting}
              onCheckedChange={(checked) => handleControlChange('enableSorting', !!checked)}
            />
            <label htmlFor="enableSorting" className="text-sm">Sorting</label>
          </div>
          <div className="flex items-center space-x-2">
            <Checkbox
              id="enableColumnVisibility"
              checked={controls.enableColumnVisibility}
              onCheckedChange={(checked) => handleControlChange('enableColumnVisibility', !!checked)}
            />
            <label htmlFor="enableColumnVisibility" className="text-sm">Column Visibility</label>
          </div>
          {/* Add more controls as needed */}
        </div>
      </div>

      {/* DataTable with Dynamic Props */}
      <DataTable
        columns={columns}
        data={data}
        tableId="dynamic-controls-table"
        
        // Dynamic controls from state
        enableSelection={controls.enableSelection}
        enableFiltering={controls.enableFiltering}
        enableGlobalSearch={controls.enableGlobalSearch}
        enableSorting={controls.enableSorting}
        enableMultiSort={controls.enableMultiSort}
        enableColumnVisibility={controls.enableColumnVisibility}
        enableColumnReorder={controls.enableColumnReorder}
        enableColumnResize={controls.enableColumnResize}
        enableColumnFreeze={controls.enableColumnFreeze}
        showColumnBorders={controls.showColumnBorders}
        
        // Fixed properties
        selectionMode="multiple"
        pageSizeOptions={[5, 10, 20]}
        initialPageSize={10}
      />
    </div>
  )
}

Benefits of Dynamic Controls

  • User Experience: Allow users to customize their table experience
  • Feature Discovery: Help users understand available features
  • Flexible Interfaces: Create adaptive UIs that respond to user preferences
  • No Code Changes: The DataTable component remains unchanged
  • Real-time Updates: Features can be toggled instantly without page refresh

Supported Dynamic Properties

All these properties can be controlled dynamically:

  • enableSelection - Row selection functionality
  • enableFiltering - Column filtering
  • enableGlobalSearch - Global search across all columns
  • enableSorting - Column sorting
  • enableMultiSort - Multi-column sorting
  • enableColumnVisibility - Show/hide columns
  • enableColumnReorder - Drag to reorder columns
  • enableColumnResize - Resize columns by dragging
  • enableColumnFreeze - Freeze columns to left/right
  • showColumnBorders - Display column borders

Quick Start Page (minimal)

Create a simple page component (e.g., src/pages/ExamplePage.tsx) and paste the following:

import { DataTable, type ColumnDef } from "@algodomain/smart-datatable"
import "@algodomain/smart-datatable/style.css"

type Task = {
  id: string
  title: string
}

const columns: ColumnDef<Task>[] = [
  { id: "id", header: "ID", accessorKey: "id", sortable: true, filterable: true, dataType: "string" },
  { id: "title", header: "Title", accessorKey: "title", sortable: true, filterable: true, dataType: "string", textWrap: true },
]

const data: Task[] = [
  { id: "1", title: "First task" },
  { id: "2", title: "Second task" },
]

export default function ExamplePage() {
  return (
    <div className="p-4">
      <DataTable
        columns={columns}
        data={data}
        enableFiltering
        enableSorting
        pageSizeOptions={[5, 10, 20]}
        initialPageSize={5}
        showColumnBorders
      />
    </div>
  )
}

Make sure your Tailwind entry (e.g., src/index.css) sources the package so class names are included during build:

/* Ensure Tailwind scans DataTable package classes */
@source "../node_modules/@algodomain/smart-datatable/dist/index.js";
/* OR */
@source "../node_modules/@algodomain/smart-datatable/dist/index.cjs";

Upcoming

  • Authentication support for mode="server" and mode="auto":
    • Access token and refresh token handling for secure API requests
    • Built-in hooks to inject auth headers in server requests
    • Graceful token refresh and retry behavior
    • Backward-compatible configuration via new props