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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@insticc/react-datagrid-2

v1.1.39

Published

A powerful and flexible React data grid component built on top of Material React Table, providing advanced features for data visualization, filtering, sorting, pagination, and row selection.

Readme

DataGrid Component

A powerful and flexible React data grid component built on top of Material React Table, providing advanced features for data visualization, filtering, sorting, pagination, and row selection.

Table of Contents


Installation

npm install @insticc/react-datagrid-2

Required Dependencies

npm install react prop-types material-react-table semantic-ui-react @mui/material @mui/x-date-pickers date-fns bootstrap semantic-ui-css

Basic Usage

import React, { useState } from 'react';
import { DataGrid } from '@insticc/react-datagrid-2';

function MyComponent() {
  const [selectedRows, setSelectedRows] = useState([]);

  const columns = [
    { accessorKey: 'id', header: 'ID', type: 'text' },
    { accessorKey: 'name', header: 'Name', type: 'text' },
    { accessorKey: 'email', header: 'Email', type: 'email' },
    { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
  ];

  const data = [
    { id: '1', name: 'John Doe', email: '[email protected]', createdAt: '2025-01-15' },
    { id: '2', name: 'Jane Smith', email: '[email protected]', createdAt: '2025-02-20' },
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={data}
      rowKey="id"
      selectData={setSelectedRows}
    />
  );
}

Props Reference

Core Props

columns (required)

  • Type: Array<ColumnDefinition>
  • Description: Array of column definitions that determine how data is displayed
  • Example:
const columns = [
  {
    accessorKey: 'name',        // Key to access data (use with accessorFn or alone)
    header: 'Full Name',        // Column header text
    type: 'text',               // Cell type - formatter applied automatically
    
    // Data Access
    accessorFn: (row) => row.firstName + ' ' + row.lastName,
    
    // Filtering & Sorting
    enableSorting: true,        // Enable/disable sorting (default: true)
    enableColumnFilter: true,   // Enable/disable filtering (default: true)
    enableColumnFilterModes: true, // Allow changing filter modes (default: true)
    filterFn: 'contains',       // Filter function type (default: 'contains')
    sortingFn: 'basic',         // Sorting function (default: 'basic' or custom for dates)
    isDateColumn: false,        // Special handling for dates (default: false)
    
    // Display
    cellClass: 'custom-class',  // CSS class wrapping cell content
    Cell: CustomComponent,      // Optional: Custom cell renderer (receives typeValue)
    enableResizing: true,       // Allow column resizing (default: true)
    grow: true,                 // Column can grow (default: true)
    enableClickToCopy: false,   // Enable click-to-copy (default: false)
    enableColumnActions: false, // Show column actions menu (default: false)
  }
];

Column Rendering Modes:

  • type only: Formatter applied automatically
  • type + cellClass: Formatted content wrapped in div with CSS class
  • type + Cell: Custom component receives typeValue (formatted content) as prop
  • Cell only: Full custom rendering without type formatter

createRows (required)

  • Type: Array<Object>
  • Description: Array of data objects to display in the grid
  • Example:
const data = [
  { id: 1, name: 'John', email: '[email protected]' },
  { id: 2, name: 'Jane', email: '[email protected]' }
];

rowKey (required)

  • Type: string
  • Description: Property name used as unique identifier for each row
  • Example: rowKey="id" or rowKey="uuid"

selectData (required)

  • Type: function
  • Description: Callback function that receives selected rows whenever selection changes
  • Signature: (selectedRows: Array<Object>) => void
  • Example:
const handleSelection = (rows) => {
  console.log('Selected rows:', rows);
  console.log('Selected IDs:', rows.map(r => r.id));
};

<DataGrid selectData={handleSelection} />

Column Configuration

Understanding accessorKey vs accessorFn

The DataGrid provides two ways to access data from your rows:

accessorKey (Simple Access)
  • Type: string
  • Use when: You want to access a property directly from the row object
  • Example:
{
  accessorKey: 'name',  // Accesses row.name
  header: 'Name'
}
accessorFn (Custom Access)
  • Type: (row: Object) => any
  • Use when: You need to compute or transform the value from row data
  • Receives: The complete row object as parameter
  • Returns: The value to be used for display, filtering, and sorting
  • Priority: Overrides accessorKey if both are defined
  • Examples:
// Example 1: Handle null/undefined values with fallback
{
  accessorKey: 'acronym',
  accessorFn: (row) => row.acronym ?? '',
  header: 'Acronym',
  type: 'text'
}

// Example 2: Access nested object properties
{
  accessorKey: 'paperCount',
  accessorFn: (row) => row.numberPapers?.value ?? 0,
  header: 'Papers',
  type: 'integer'
}

// Example 3: Combine multiple fields
{
  accessorKey: 'fullName',
  accessorFn: (row) => `${row.firstName} ${row.lastName}`,
  header: 'Full Name',
  type: 'text'
}

// Example 4: Conditional logic
{
  accessorKey: 'status',
  accessorFn: (row) => row.isActive ? 'Active' : 'Inactive',
  header: 'Status',
  type: 'text'
}

// Example 5: Complex calculations
{
  accessorKey: 'total',
  accessorFn: (row) => (row.price || 0) * (row.quantity || 0),
  header: 'Total',
  type: 'currency'
}

// Example 6: Array to string conversion
{
  accessorKey: 'tags',
  accessorFn: (row) => row.tags?.join(', ') ?? 'No tags',
  header: 'Tags',
  type: 'text'
}

// Example 7: Date formatting for sorting
{
  accessorKey: 'createdDate',
  accessorFn: (row) => row.createdAt ? new Date(row.createdAt).getTime() : 0,
  header: 'Created',
  type: 'date',
  isDateColumn: true
}

Important Notes:

  • accessorFn is executed for every cell render, filter, and sort operation
  • Keep the function lightweight to avoid performance issues
  • The returned value is what gets filtered and sorted (not the original cell display)
  • When using accessorFn, you typically still need accessorKey as a unique identifier for the column
  • accessorFn value is passed to the type formatter (if type is specified)

Performance Tip:

// Bad - Creates new object every time
accessorFn: (row) => ({ value: row.data, label: row.name })

// Good - Returns simple value
accessorFn: (row) => row.data?.value ?? 0

columnVisibilityState

  • Type: object
  • Default: {}
  • Description: Controls which columns are visible/hidden
  • Example:
columnVisibilityState={{
  email: false,    // Hide email column
  phone: true,     // Show phone column
  id: false        // Hide ID column
}}

columnOrder

  • Type: Array<string>
  • Default: []
  • Description: Defines the order of columns by their accessorKey
  • Example:
columnOrder={['name', 'email', 'createdAt', 'id']}

Column Filter Functions (filterFn)

Each column can define its own filter function to determine how user input is matched against cell values.

  • Type: string | function
  • Default: 'contains' (or undefined for date columns)
  • Description: Defines how column values are filtered when user enters a filter value

Available Built-in Filter Functions:

  • 'contains' - Case-insensitive substring match (default for most columns)
  • 'fuzzy' - Fuzzy matching algorithm
  • 'equals' - Exact match
  • 'startsWith' - Match at beginning of value
  • 'endsWith' - Match at end of value
  • 'notEquals' - Does not match exactly
  • 'between' - Value is between two numbers
  • 'betweenInclusive' - Value is between two numbers (inclusive)
  • 'greaterThan' - Greater than number
  • 'lessThan' - Less than number
  • 'greaterThanOrEqualTo' - Greater than or equal to number
  • 'lessThanOrEqualTo' - Less than or equal to number
  • 'empty' - Is empty or null
  • 'notEmpty' - Is not empty or null
  • 'regex' - Regular expression match (custom)
  • 'logical' - Logical expression filter (custom)

Examples:

const columns = [
  // String search - contains
  {
    accessorKey: 'name',
    header: 'Name',
    type: 'text',
    filterFn: 'contains'  // Default substring search
  },

  // Fuzzy search - useful for typos
  {
    accessorKey: 'email',
    header: 'Email',
    type: 'email',
    filterFn: 'fuzzy'  // More forgiving matching
  },

  // Exact match
  {
    accessorKey: 'status',
    header: 'Status',
    type: 'text',
    filterFn: 'equals'  // Must match exactly
  },

  // Numeric range
  {
    accessorKey: 'price',
    header: 'Price',
    type: 'currency',
    filterFn: 'between'  // Filter: "10 to 100"
  },

  // Date columns - no filter by default (date picker used instead)
  {
    accessorKey: 'createdAt',
    header: 'Created Date',
    type: 'date',
    isDateColumn: true
    // filterFn is undefined for dates - date picker is shown instead
  },

  // Pattern matching
  {
    accessorKey: 'code',
    header: 'Product Code',
    type: 'text',
    filterFn: 'startsWith'  // Match codes starting with input
  },

  // Custom filter function
  {
    accessorKey: 'amount',
    header: 'Amount',
    type: 'currency',
    filterFn: (row, id, filterValue) => {
      // Custom logic: filter amounts divisible by a number
      const amount = row.getValue(id);
      const divisor = parseInt(filterValue, 10);
      if (!divisor || isNaN(divisor)) return true;
      return amount % divisor === 0;
    }
  },

  // Combination: custom accessor with specific filter
  {
    accessorKey: 'fullName',
    accessorFn: (row) => `${row.firstName} ${row.lastName}`,
    header: 'Full Name',
    type: 'text',
    filterFn: 'fuzzy'  // Fuzzy match on combined name
  }
];

Custom Filter Function Signature:

(row: Row, columnId: string, filterValue: string | number) => boolean

Custom Filter Example - Case Sensitive Match:

{
  accessorKey: 'code',
  header: 'Code',
  filterFn: (row, id, filterValue) => {
    const value = row.getValue(id);
    return String(value).includes(filterValue);  // Case sensitive
  }
}

Column Header Helper

Any column can show a small info icon ⓘ next to its header title, surfacing extra context via an interactive hover panel, a click-to-open modal (closable via its X button or by clicking outside), or both.

helper

  • Type: boolean
  • Default: false
  • Description: Shows the info icon next to the column's header title.

helperType

  • Type: Array<'onhover' | 'onclick'>
  • Default: ['onhover', 'onclick']
  • Description: Which interactions reveal helperContent. Include only one to restrict it to a single interaction.
    • 'onhover' — shows helperContent in an MUI Popover anchored to the icon. Unlike a plain tooltip, its content stays interactive, so clickable items work while hovering.
    • 'onclick' — opens helperContent in an MUI Modal, centered on screen, closable via its X button or by clicking outside.

helperContent

  • Type: object
  • Properties:
    • title (string) — bold heading.
    • description (string) — descriptive text below the title.
    • items (Array<Item>) — a flat list of items, or up to two levels when any entry also has its own items (a group). Both levels share the same shape:
      • icon (string | element) — image URL or React element rendered before the text.
      • text (string) — the item's (or group's) label.
      • acronym (string) — shown in parentheses right after the text, e.g. Portugal (PT).
      • clickable (boolean) — if true, shows a tap icon next to the item/group heading, indicating its row is clickable.
      • items (Array<Item>, groups only) — nested leaf items rendered below the group's own icon/text/acronym/clickable line.
    • verticalList (boolean, default false) — true renders each group's items as a bulleted list (<ul>); false joins them inline, separated by ;.
    • hasNotes (boolean, default false) — true shows a notes line, in italic gray, below the description; false hides it entirely.
    • notes (string) — the notes text shown when hasNotes is true. If omitted, a default notes string is shown instead.
    • style (object) — inline CSS merged into the content wrapper (the block rendered inside the hover popover / modal), e.g. { maxHeight: 400, overflowY: 'auto' }.
  • Example:
{
  accessorKey: 'country',
  header: 'Country',
  type: 'countryFlag',
  helper: true,
  helperType: ['onclick'], // modal only, no tooltip
  helperContent: {
    title: 'Country codes',
    verticalList: true,
    style: { maxHeight: 400, overflowY: 'auto' }, // scroll long content instead of growing the modal
    items: [
      {
        text: 'Europe',
        acronym: 'EU',
        items: [{ icon: 'https://flagcdn.com/24x18/pt.png', text: 'Portugal', acronym: 'PT' }],
      },
      {
        text: 'Americas',
        acronym: 'AM',
        clickable: true, // shows a tap icon next to the group heading
        items: [{ icon: 'https://flagcdn.com/24x18/br.png', text: 'Brazil', acronym: 'BR', clickable: true }],
      },
    ],
  },
}

helperStyle

  • Type: object
  • Description: Inline CSS merged into the modal window (the popup box itself), overriding its default position/size/appearance. Only applies to the 'onclick' modal, not the 'onhover' popover.
  • Example:
{
  accessorKey: 'country',
  header: 'Country',
  helper: true,
  helperType: ['onclick'],
  helperStyle: { width: 480, backgroundColor: '#fafafa' },
  helperContent: { title: 'Country codes', items: [/* ... */] },
}

Actions & Toolbar

actions

  • Type: Array<ActionObject>
  • Default: null
  • Description: Array of custom action buttons displayed in the toolbar
  • Action Object Properties:
    • name (string): Button label
    • function (function, required): Callback when button is clicked - receives selected rows or table instance
    • tooltip (string): Tooltip text on hover
    • color (string): Button color - one of: 'blue', 'red', 'green', 'yellow', 'orange', 'black', 'grey', 'teal', 'brown', 'violet', 'purple', 'olive', 'pink'
    • icon (string|element): Icon name (Semantic UI) or React element
    • selectionMode (string): When button is enabled:
      • 'single' - Enabled only when exactly one row is selected
      • 'multi' - Enabled when one or more rows are selected
      • 'always' - Always enabled regardless of selection
    • confirmMessage (string|element): Confirmation message before action executes
    • hasConfirmMessage (boolean): Whether to show confirmation dialog
    • disabled (boolean): Manually disable the button
    • visible (boolean): Show/hide the button (default: true)
    • toggle (boolean): Render as toggle button
    • active (boolean): Toggle button active state (when toggle: true)
    • key (string): Unique React key (defaults to name)
  • Example:
actions={[
  {
    name: 'Delete',
    function: (selectedRows) => handleDelete(selectedRows),
    tooltip: 'Delete selected rows',
    color: 'red',
    icon: 'trash',
    selectionMode: 'multi',
    hasConfirmMessage: true,
    confirmMessage: 'Are you sure you want to delete these rows?'
  },
  {
    name: 'Edit',
    function: (selectedRows) => handleEdit(selectedRows[0]),
    tooltip: 'Edit selected row',
    color: 'blue',
    icon: 'edit',
    selectionMode: 'single'
  },
  {
    name: 'Add New',
    function: () => handleAdd(),
    tooltip: 'Add new record',
    color: 'green',
    icon: 'plus',
    selectionMode: 'always'
  },
  {
    name: 'Archive Mode',
    function: () => toggleArchiveMode(),
    tooltip: 'Toggle archive view',
    color: 'grey',
    icon: 'archive',
    toggle: true,
    active: isArchiveMode,
    selectionMode: 'always'
  }
]}

filterActions

  • Type: Array<FilterActionObject>
  • Default: null
  • Description: Array of toggle filter action buttons displayed in the toolbar for showing/hiding data based on filters
  • Filter Action Object Properties:
    • name (string): Button label
    • function (function, required): Callback when button is toggled - receives current state
    • state (boolean): Current filter state (true = filter active/hidden, false = filter inactive/shown)
    • key (string): Unique React key (defaults to name)
    • tooltip (string): Tooltip text on hover
    • disabled (boolean): Manually disable the button
    • visible (boolean): Show/hide the button (default: true)
  • Button Appearance:
    • When state=true: Orange color with eye-slash icon (items hidden)
    • When state=false: Green color with eye icon (items shown)
  • Example:
const [hideCompleted, setHideCompleted] = useState(false);
const [hideArchived, setHideArchived] = useState(true);

filterActions={[
  {
    name: 'Completed',
    state: hideCompleted,
    function: () => setHideCompleted(!hideCompleted),
    tooltip: 'Toggle completed items visibility',
    key: 'filter-completed'
  },
  {
    name: 'Archived',
    state: hideArchived,
    function: () => setHideArchived(!hideArchived),
    tooltip: 'Toggle archived items visibility',
    disabled: false,
    visible: true
  },
  {
    // Dynamic button text based on state
    state: hideEvents,
    name: hideEvents ? "Hiding Events" : "Showing Events",
    tooltip: hideEvents ? "Show Events" : "Hide Events",
    function: () => setHideEvents(!hideEvents),
    visible: !!handleHideEvents,  // Only show if handler exists
  }
]}

extraActions

  • Type: Array<ExtraActionObject>
  • Default: null
  • Description: Additional custom action buttons displayed on the right side of the toolbar
  • Extra Action Object Properties:
    • function (function, required): Callback when button is clicked
    • content (string|element): Button content/label - if not provided, falls back to name
    • name (string): Button label; used as fallback for content when content is not provided
    • tooltip (string): Tooltip text on hover
    • icon (string|element): Icon name or React element
    • style (object): Custom CSS styles for the button
    • propsButton (object): Additional props passed to Semantic UI Button component (deprecated in favor of spreading props directly)
    • ...rest (any): Any additional props are spread directly onto the Button component, allowing flexible customization without needing propsButton
    • visible (boolean): Show/hide the button (default: true)
  • Example:
extraActions={[
  {
    function: () => openSettings(),
    name: 'Settings',  // Used as both label and fallback for content
    tooltip: 'Open settings',
    icon: 'setting',
    style: { backgroundColor: '#f0f0f0' }
  },
  {
    function: () => downloadReport(),
    content: 'Download',
    tooltip: 'Download report',
    icon: 'download',
    loading: isDownloading  // Passed directly as prop instead of propsButton
  },
  {
    function: () => openMenu(),
    name: 'Menu',
    disabled: isLoading,  // Additional props spread directly
    primary: true
  }
]}

enableTopToolbar

  • Type: boolean
  • Default: true
  • Description: Show/hide the top toolbar containing actions and pagination

enableBottomToolbar

  • Type: boolean
  • Default: false
  • Description: Show/hide the bottom toolbar

hasClearFiltersBtn

  • Type: boolean
  • Default: true
  • Description: Show/hide the "Clear Filters" button in toolbar

hasClearSelectionBtn

  • Type: boolean
  • Default: true
  • Description: Show/hide the "Clear Selection" button in toolbar
  • Note: Only visible when disableSelect={false} or disableRows array has items

disableAllActions

  • Type: boolean
  • Default: false
  • Description: Hide all action buttons in the top toolbar

disableSideActions

  • Type: boolean
  • Default: false
  • Description: Hide side action buttons (export, cache, clear filters, help) while keeping main actions visible

gridHelper

  • Type: object | null
  • Default: null
  • Description: Adds a help button with custom content in a modal dialog
  • Required Properties (if defined):
    • title (string|element, required): Help dialog title
    • content (string|element, required): Help dialog content
  • Example:
gridHelper={{
  title: 'Grid Instructions',
  content: (
    <div>
      <h3>How to use this grid:</h3>
      <ul>
        <li>Use the filters above each column to search data</li>
        <li>Click rows to select them</li>
        <li>Use action buttons to perform operations</li>
        <li>Export data using the Excel or PDF buttons</li>
      </ul>
    </div>
  )
}}

Export Options

hasExcelExport

  • Type: boolean
  • Default: false
  • Description: Enable Excel export button in the toolbar

hasPdfExport

  • Type: boolean
  • Default: false
  • Description: Enable PDF export button in the toolbar

exportColumns

  • Type: Array<ColumnDefinition>
  • Default: null
  • Description: Column definitions used exclusively for export (Excel and PDF). When provided, these columns override the main columns prop for export purposes, allowing you to export a different set of columns (or with different formatting) than what is displayed in the grid. Supports accessorKey, accessorFn, header, and type. If null, the main columns prop is used.
  • Example:
exportColumns={[
  { accessorKey: 'fullName', header: 'Name' },
  { accessorKey: 'email', header: 'Email' },
  { accessorKey: 'eventAcronym', header: 'Event' },
  {
    accessorKey: 'isUsingBus', header: 'Bus',
    accessorFn: ({ isUsingBus }) => !isUsingBus ? 'No Need' : ''
  },
  { accessorKey: '_deletedAt', header: 'Deleted At', type: 'datetime' },
  { accessorKey: 'justification', header: 'Justification', type: 'htmlText' },
]}

exportfileName

  • Type: string
  • Default: "data"
  • Description: Default file name (without extension) pre-filled in the export modal. The user can still change it before confirming the export.

pdfExportTitle

  • Type: string
  • Default: "Report"
  • Description: Title printed at the top of the exported PDF document, below the logo (if any). The user can change it in the export modal before confirming.

pdfExportBrand

  • Type: object
  • Default: {}
  • Description: Branding configuration applied to the PDF layout. Merged with the internal defaults, so you only need to provide the properties you want to override.
  • Properties:

| Property | Type | Default | Description | | ---------------- | -------- | ----------- | ---------------------------------------------- | | primaryColor | string | '#0f4c81' | Header background color (hex) | | secondaryColor | string | '#ffffff' | Header text color (hex) | | accentColor | string | '#e8f0fe' | Alternating row fill color (hex) | | fontName | string | undefined | Font name used in the PDF | | logoBase64 | string | null | Base64-encoded PNG logo placed above the title | | logoWidth | number | 50 | Logo width in PDF units | | logoHeight | number | 20 | Logo height in PDF units |

  • Example:
pdfExportBrand={{
  primaryColor: '#1a237e',
  secondaryColor: '#ffffff',
  accentColor: '#e8eaf6',
  logoBase64: myLogoBase64String,
  logoWidth: 60,
  logoHeight: 24,
}}

Export Behavior:

  • Clicking an export button opens a confirmation modal where the user can adjust the file name and (for PDF) the document title.
  • The modal also previews the list of columns that will be exported.
  • Export rows are resolved by applying each column's Cell formatter (or type formatter) to produce plain-text values; React elements are safely stringified to their raw value.
  • exportColumns are processed through createColumns(), so all standard column features (type, accessorFn, Cell) are supported.
  • Filtered rows are used when an MRT table instance is passed to ExportActions; otherwise all createRows are exported.

Selection & Interaction

disableSelect

  • Type: boolean
  • Default: false
  • Description: Completely disable row selection checkboxes and click-to-select behavior

enableMultiRowSelection

  • Type: boolean
  • Default: true
  • Description: Allow selecting multiple rows at once
  • Behavior:
    • true - Users can select multiple rows using checkboxes or Shift+Click
    • false - Only one row can be selected at a time

selectAllMode

  • Type: string
  • Default: 'page'
  • Options: 'page', 'all'
  • Description:
    • 'page' - "Select All" checkbox selects only rows on current page
    • 'all' - "Select All" checkbox selects all filtered rows across all pages

selectedIds

  • Type: Array
  • Default: []
  • Description: Array of row IDs that should be pre-selected when grid loads
  • Example:
selectedIds={[1, 5, 10]}  // Pre-select rows with these IDs
  • Note: Component syncs automatically when this prop changes

disableRows

  • Type: Array
  • Default: []
  • Description: Array of row IDs (based on rowKey) that should be disabled and cannot be selected
  • Example:
disableRows={[3, 7, 9]}  // Disable selection for these row IDs
  • Visual: Disabled rows are shown with gray background (#e3e3e3)

hasSubRows

  • Type: boolean
  • Default: false
  • Description: Enable support for hierarchical/nested rows
  • Requirements: Data must include subRows property for parent rows
  • Example Data:
const data = [
  {
    id: 1,
    name: 'Parent Row',
    subRows: [
      { id: '1.1', name: 'Child Row 1' },
      { id: '1.2', name: 'Child Row 2' }
    ]
  }
];

enableExpanding

  • Type: boolean
  • Default: false
  • Description: Show expand/collapse icons for rows with subRows
  • Requires: hasSubRows={true}

Pagination & Display

enablePagination

  • Type: boolean
  • Default: true
  • Description: Enable/disable pagination controls

pagination

  • Type: string
  • Default: 'both'
  • Options: 'top', 'bottom', 'both'
  • Description: Position of pagination controls
  • Behavior:
    • 'top' - Pagination integrated into the top toolbar alongside action buttons
    • 'bottom' - Pagination appears in the bottom toolbar; when disabled or this mode is set, the selection count (Selected/Filtered/Total) is displayed in the top toolbar's side actions area
    • 'both' - Pagination appears in both top and bottom toolbars
  • Note: When enablePagination={false}, the selection count display still appears in the side actions

pageSize

  • Type: number
  • Default: 150
  • Description: Number of rows displayed per page initially

itemsPerPage

  • Type: Array<number>
  • Default: [50, 100, 150]
  • Description: Options available in the rows-per-page dropdown
  • Example:
itemsPerPage={[10, 25, 50, 100, 200]}

Styling & Layout

rowHeight

  • Type: number
  • Default: 75
  • Description: Minimum height of each row in pixels

fontSize

  • Type: number
  • Default: 14
  • Description: Base font size for grid content in pixels
  • Compact Mode: When enableCompactStyleMode={true}, responsive sizing is used: clamp(fontSize-3px, 1.1vw, fontSize)

gridHeight

  • Type: number | string
  • Default: 600
  • Description: Maximum height of the grid container
  • Examples:
gridHeight={600}              // 600px fixed height
gridHeight="80vh"             // 80% of viewport height
gridHeight="calc(100vh - 200px)" // Dynamic height calculation

enableCompactStyleMode

  • Type: boolean
  • Default: false
  • Description: Enable compact styling with reduced padding and responsive font sizes
  • Features:
    • Reduced cell padding (2px vs auto)
    • Responsive font sizing using CSS clamp()
    • Tighter filter input heights (17px vs default)
    • Reduced column header spacing
    • Optimized for displaying dense data

getRowStyle

  • Type: function
  • Description: Custom function to apply conditional styles to rows based on data
  • Signature: ({ row }) => object
  • Example:
getRowStyle={({ row }) => {
  const styles = {};
  
  if (row.original.status === 'active') {
    styles.backgroundColor = '#e8f5e9';
  }
  
  if (row.original.priority === 'high') {
    styles.color = 'red';
    styles.fontWeight = 'bold';
  }
  
  if (row.original.isExpired) {
    styles.opacity = 0.6;
    styles.textDecoration = 'line-through';
  }
  
  return styles;
}}

enableFixedHeader

  • Type: boolean
  • Default: true
  • Description: Pin column headers to top when scrolling vertically
  • Implementation: Uses CSS sticky positioning with class grid-sticky-header

enableFixedActions

  • Type: boolean
  • Default: false
  • Description: Pin action toolbar to top when scrolling
  • Requires: enableFixedHeader={true}
  • Implementation: Uses CSS sticky positioning with class grid-sticky-actions

Advanced Features

enableGlobalFilter

  • Type: boolean
  • Default: false
  • Description: Show global search input that filters across all columns

globalFilterFn

  • Type: string
  • Default: 'contains'
  • Options: 'contains', 'fuzzy', 'between', 'equals', 'greaterThan', 'lessThan', 'notEquals', 'lessThanOrEqualTo', 'greaterThanOrEqualTo', 'empty', 'notEmpty', 'startsWith', 'endsWith', 'betweenInclusive'
  • Description: Filter function used for global search

enableColumnFilterModes

  • Type: boolean
  • Default: true
  • Description: Allow users to change filter type per column (contains, equals, regex, etc.)
  • Available Modes: Rendered through ColumnFilter component

enableVirtualization

  • Type: boolean
  • Default: false
  • Description: Enable row and column virtualization for large datasets
  • Recommended: For grids with 1000+ rows
  • Configuration:
    • Row virtualizer: overscan: 5
    • Column virtualizer: overscan: columns.length
    • Scroll-to-top on sort change

enableFullScreenToggle

  • Type: boolean
  • Default: false
  • Description: Show fullscreen toggle button in toolbar

enableDensityToggle

  • Type: boolean
  • Default: false
  • Description: Show density toggle button (compact/comfortable/spacious)

Cache & Updates

updateCache

  • Type: function
  • Default: undefined
  • Description: Callback function triggered when cache update button is clicked
  • Signature: () => void
  • Example:
updateCache={() => {
  fetchLatestData();
}}
  • Note: Cache button only appears when this prop is provided

cacheUpdateText

  • Type: string
  • Default: undefined
  • Description: Tooltip text displayed on hover over the cache update button
  • Example: "Refresh data from server"

cacheUpdating

  • Type: boolean
  • Default: false
  • Description: Shows loading state on cache update button
  • Visual: Changes button icon to loading spinner
  • Disables: Button is disabled while true

Callbacks

onVisibleRowsChange

  • Type: function
  • Description: Called whenever the visible rows change (filtering, sorting, pagination)
  • Signature: (visibleRows: Array<Object>) => void
  • Example:
onVisibleRowsChange={(rows) => {
  console.log('Currently visible:', rows.length);
  updateDashboardStats(rows);
}}

Column Types

The DataGrid supports various pre-built cell types via the type property in column definitions. These formatters are automatically applied without requiring custom cell components.

Text Types

  • text - Plain text display
  • textTitle - Bold text (font-weight: bold)
  • textDescription - Gray text (#666666)
  • textSmall - Small font size text

Date Types

  • date - Date only (no time) - Format: locale-specific date
  • datetime - Date with time - Format: locale-specific datetime

Number Types

  • number - Raw number display
  • integer - Rounded integer (Math.round)
  • currency - EUR currency format (€1,234.56)
  • percentage - Percentage format (12.34%)

Boolean Types

  • boolean - Renders Yes / No as plain text. Returns null for null/undefined.
  • booleanBadge - Renders Yes / No as a colored badge: green for true, red for false. Returns null for null/undefined.

HTML Types

  • htmlText - Strips all HTML tags and collapses whitespace, returning a clean plain-text string. Useful for exporting HTML-formatted fields.
  • htmlFormat - Renders raw HTML using dangerouslySetInnerHTML. Use only with trusted, sanitized content.

Link Types

  • email - Clickable mailto link (<a href="mailto:...">)
  • phone - Clickable tel link (<a href="tel:...">)
  • link - External link that opens in new tab (target="_blank")

Complex Types

  • array - Comma-separated array values
  • json - Formatted JSON display with indentation
  • countryFlag - Country flag image (requires ISO2 country code)
  • persons - List of persons with "et al." for 3+ people

Example with Types

const columns = [
  { accessorKey: 'name', header: 'Name', type: 'textTitle' },
  { accessorKey: 'description', header: 'Description', type: 'textDescription' },
  { accessorKey: 'email', header: 'Email', type: 'email' },
  { accessorKey: 'phone', header: 'Phone', type: 'phone' },
  { accessorKey: 'website', header: 'Website', type: 'link' },
  { accessorKey: 'salary', header: 'Salary', type: 'currency' },
  { accessorKey: 'completion', header: 'Progress', type: 'percentage' },
  { accessorKey: 'createdAt', header: 'Created', type: 'date', isDateColumn: true },
  { accessorKey: 'lastUpdated', header: 'Last Updated', type: 'datetime', isDateColumn: true },
  { accessorKey: 'country', header: 'Country', type: 'countryFlag' },
  { accessorKey: 'tags', header: 'Tags', type: 'array' },
  { accessorKey: 'metadata', header: 'Metadata', type: 'json' },
  { accessorKey: 'authors', header: 'Authors', type: 'persons' },
];

Custom Cell Renderers with Type Support

You have multiple options for cell rendering, each serving different use cases:

Option 1: Using Type Alone (Simplest)

Best for: Standard formatting without custom logic

const columns = [
  {
    accessorKey: 'price',
    header: 'Price',
    type: 'currency'  // Automatically formatted as €1,234.56
  }
];
// No custom Cell needed - formatter is applied automatically

Option 2: Type + cellClass

Best for: Adding CSS styling to formatted content

const columns = [
  {
    accessorKey: 'status',
    header: 'Status',
    type: 'text',
    cellClass: 'status-badge'  // Formatted text wrapped in <div class="status-badge">
  }
];

Option 3: Type + Custom Cell (Advanced)

Best for: Custom logic or styling while preserving type formatting

// Custom cell that uses the type formatter and adds custom styling
const CustomStatusCell = ({ typeValue, cell, row }) => {
  const rawValue = cell.getValue();
  const formattedValue = typeValue;  // Pre-formatted by type formatter
  
  return (
    <div style={{ 
      color: rawValue === 'active' ? 'green' : 'red',
      fontWeight: 'bold',
      padding: '4px 8px',
      borderRadius: '4px',
      backgroundColor: rawValue === 'active' ? '#e8f5e9' : '#ffebee'
    }}>
      {formattedValue || rawValue}  {/* Use formatted value or fallback */}
    </div>
  );
};

const columns = [
  {
    accessorKey: 'status',
    header: 'Status',
    type: 'text',              // Formatter is applied first
    Cell: CustomStatusCell,    // Custom component receives typeValue prop
  }
];

Option 4: Custom Cell Only (No Type)

Best for: Complete custom rendering without any formatter

const CustomCell = ({ cell, row }) => {
  const value = cell.getValue();
  
  return (
    <div className="custom-cell">
      <strong>{value}</strong>
      <span className="badge">{row.original.count}</span>
    </div>
  );
};

const columns = [
  {
    accessorKey: 'name',
    header: 'Name',
    Cell: CustomCell  // No type - full control over rendering
  }
];

Custom Cell Props Reference

When using a custom Cell component, you receive these props:

{
  cell: Object,           // MRT cell instance
  row: Object,            // MRT row instance
  table: Object,          // MRT table instance
  typeValue: any,         // Formatted value from type formatter (if type is defined)
  // Standard MRT props...
}

Important: Access row.original to get the original data object.


How Cell Rendering Works:

  1. accessorFn/accessorKey evaluated: Value is extracted from row data
  2. Type formatter applied: If type is specified, DEFAULT_CELL_TYPES[type] processes the value
  3. Content assigned: Formatted value becomes the base content
  4. Custom Cell receives props: If Cell is defined, it receives:
    • typeValue: The pre-formatted value
    • All standard MRT cell props
  5. CSS wrapper: If cellClass is defined, final content is wrapped in <div className={cellClass}>

Rendering Priority:

Raw Data → accessorFn → Type Formatter → typeValue → Custom Cell → cellClass Wrapper → Final Output

When to use each approach:

  • Use type only for standard formatting (95% of cases)
  • Use type + cellClass for simple styling needs
  • Use type + Cell when you need formatting AND custom logic
  • Use Cell only for completely custom rendering

Examples

Example 1: Basic Grid with Selection

import React, { useState } from 'react';
import DataGrid from '@insticc/react-datagrid-2';

function UserGrid() {
  const [selected, setSelected] = useState([]);

  const columns = [
    { accessorKey: 'id', header: 'ID', type: 'integer' },
    { accessorKey: 'name', header: 'Name', type: 'textTitle' },
    { accessorKey: 'email', header: 'Email', type: 'email' },
    { accessorKey: 'role', header: 'Role', type: 'text' },
    { accessorKey: 'createdAt', header: 'Joined', type: 'date', isDateColumn: true },
  ];

  const users = [
    { id: 1, name: 'John Doe', email: '[email protected]', role: 'Admin', createdAt: '2024-01-15' },
    { id: 2, name: 'Jane Smith', email: '[email protected]', role: 'User', createdAt: '2024-02-20' },
    { id: 3, name: 'Bob Johnson', email: '[email protected]', role: 'Manager', createdAt: '2024-03-10' },
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={users}
      rowKey="id"
      selectData={setSelected}
      pageSize={50}
      itemsPerPage={[25, 50, 100]}
      gridHeight={500}
    />
  );
}

Example 2: Using accessorFn for Complex Data

function ConferenceGrid() {
  const [selected, setSelected] = useState([]);

  const columns = [
    { 
      accessorKey: 'acronym',
      accessorFn: (row) => row.acronym ?? '',  // Handle null/undefined
      header: 'Acronym',
      type: 'textTitle'
    },
    { 
      accessorKey: 'fullName',
      accessorFn: (row) => `${row.shortName || ''} - ${row.year || ''}`,  // Combine fields
      header: 'Conference Name',
      type: 'text'
    },
    { 
      accessorKey: 'papers',
      accessorFn: (row) => row.numberPapers?.value ?? 0,  // Nested object with fallback
      header: 'Papers',
      type: 'integer'
    },
    { 
      accessorKey: 'averageRating',
      accessorFn: (row) => row.ratings?.average ?? 0,  // Nested with default
      header: 'Avg Rating',
      type: 'number'
    },
    { 
      accessorKey: 'status',
      accessorFn: (row) => row.isActive ? 'Active' : 'Inactive',  // Conditional
      header: 'Status',
      type: 'text'
    },
    { 
      accessorKey: 'organizers',
      accessorFn: (row) => row.organizers?.map(o => o.name).join(', ') ?? 'N/A',  // Array processing
      header: 'Organizers',
      type: 'text'
    }
  ];

  const conferences = [
    {
      id: 1,
      acronym: 'ICEIS',
      shortName: 'International Conference on Enterprise Information Systems',
      year: 2025,
      numberPapers: { value: 150, trend: 'up' },
      ratings: { average: 4.5, count: 200 },
      isActive: true,
      organizers: [{ name: 'John Doe' }, { name: 'Jane Smith' }]
    },
    {
      id: 2,
      acronym: null,  // Will be handled by accessorFn
      shortName: 'Conference on AI',
      year: 2024,
      numberPapers: null,  // Will default to 0
      ratings: { average: 3.8, count: 50 },
      isActive: false,
      organizers: []
    }
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={conferences}
      rowKey="id"
      selectData={setSelected}
      gridHeight={600}
    />
  );
}

Example 3: Grid with Filter Actions

function TaskGrid() {
  const [tasks, setTasks] = useState(initialTasks);
  const [selected, setSelected] = useState([]);
  const [hideCompleted, setHideCompleted] = useState(false);
  const [hideArchived, setHideArchived] = useState(true);

  // Filter data based on filter states
  const filteredTasks = useMemo(() => {
    return tasks.filter(task => {
      if (hideCompleted && task.status === 'completed') return false;
      if (hideArchived && task.isArchived) return false;
      return true;
    });
  }, [tasks, hideCompleted, hideArchived]);

  const filterActions = [
    {
      name: 'Completed',
      state: hideCompleted,
      function: () => setHideCompleted(!hideCompleted),
      tooltip: hideCompleted ? 'Show completed tasks' : 'Hide completed tasks',
      key: 'filter-completed'
    },
    {
      name: 'Archived',
      state: hideArchived,
      function: () => setHideArchived(!hideArchived),
      tooltip: hideArchived ? 'Show archived tasks' : 'Hide archived tasks',
      key: 'filter-archived'
    },
    {
      // Example with dynamic name and conditional visibility
      state: hideUrgent,
      name: hideUrgent ? "Hiding Urgent" : "Showing Urgent",
      tooltip: hideUrgent ? "Show urgent tasks" : "Hide urgent tasks",
      function: () => setHideUrgent(!hideUrgent),
      visible: !!setHideUrgent,  // Only show if handler exists
    }
  ];

  const columns = [
    { accessorKey: 'id', header: 'ID', type: 'integer' },
    { accessorKey: 'title', header: 'Task', type: 'textTitle' },
    { accessorKey: 'status', header: 'Status', type: 'text' },
    { accessorKey: 'dueDate', header: 'Due Date', type: 'date', isDateColumn: true },
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={filteredTasks}
      rowKey="id"
      selectData={setSelected}
      filterActions={filterActions}
      gridHeight={600}
    />
  );
}

Example 4: Hierarchical Data with SubRows

function ProjectGrid() {
  const [selectedItems, setSelectedItems] = useState([]);

  const columns = [
    { accessorKey: 'name', header: 'Name', type: 'textTitle' },
    { accessorKey: 'status', header: 'Status', type: 'text' },
    { accessorKey: 'assignee', header: 'Assignee', type: 'text' },
    { accessorKey: 'dueDate', header: 'Due Date', type: 'date', isDateColumn: true },
  ];

  const data = [
    {
      id: 1,
      name: 'Project Alpha',
      status: 'Active',
      assignee: 'John Doe',
      dueDate: '2025-06-30',
      subRows: [
        { id: '1.1', name: 'Task 1: Design', status: 'Complete', assignee: 'Jane', dueDate: '2025-02-15' },
        { id: '1.2', name: 'Task 2: Development', status: 'In Progress', assignee: 'Bob', dueDate: '2025-04-30' },
        { id: '1.3', name: 'Task 3: Testing', status: 'Not Started', assignee: 'Alice', dueDate: '2025-06-15' }
      ]
    },
    {
      id: 2,
      name: 'Project Beta',
      status: 'Planning',
      assignee: 'Jane Smith',
      dueDate: '2025-12-31',
      subRows: [
        { id: '2.1', name: 'Task 1: Requirements', status: 'In Progress', assignee: 'John', dueDate: '2025-03-01' }
      ]
    }
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={data}
      rowKey="id"
      selectData={setSelectedItems}
      hasSubRows={true}
      enableExpanding={true}
      gridHeight={500}
    />
  );
}

Example 5: Custom Styling and Virtualization

function LargeDataGrid() {
  const [selectedRows, setSelectedRows] = useState([]);

  // Custom cell with type support
  const StatusCell = ({ typeValue, cell, row }) => {
    const value = cell.getValue();
    const getColor = (status) => {
      switch (status) {
        case 'active': return 'green';
        case 'pending': return 'orange';
        case 'error': return 'red';
        default: return 'grey';
      }
    };
    
    return (
      <span style={{ 
        color: getColor(value), 
        fontWeight: 'bold',
        padding: '2px 8px',
        borderRadius: '4px',
        backgroundColor: `${getColor(value)}22`
      }}>
        {typeValue || value}
      </span>
    );
  };

  const PriorityCell = ({ cell, row }) => {
    const priority = cell.getValue();
    const icons = {
      high: '🔴',
      medium: '🟡',
      low: '🟢'
    };
    
    return (
      <span>
        {icons[priority]} {priority.toUpperCase()}
      </span>
    );
  };

  const getRowStyle = ({ row }) => {
    const styles = {};
    
    if (row.original.status === 'error') {
      styles.backgroundColor = '#ffebee';
    }
    
    if (row.original.priority === 'high') {
      styles.borderLeft = '3px solid red';
    }
    
    if (row.original.isArchived) {
      styles.opacity = 0.5;
    }
    
    return styles;
  };

  const columns = [
    { accessorKey: 'id', header: 'ID', type: 'integer' },
    { 
      accessorKey: 'status', 
      header: 'Status', 
      type: 'text',
      Cell: StatusCell
    },
    {
      accessorKey: 'priority',
      header: 'Priority',
      Cell: PriorityCell
    },
    { accessorKey: 'name', header: 'Name', type: 'text' },
    { 
      accessorKey: 'value',
      accessorFn: (row) => row.value ?? 0,  // Ensure numeric value for currency
      header: 'Value',
      type: 'currency'
    },
    { 
      accessorKey: 'progress',
      accessorFn: (row) => row.progress ?? 0,  // Ensure numeric value for percentage
      header: 'Progress',
      type: 'percentage'
    },
    { accessorKey: 'updatedAt', header: 'Updated', type: 'datetime', isDateColumn: true },
  ];

  // Generate large dataset
  const largeDataset = Array.from({ length: 5000 }, (_, i) => ({
    id: i + 1,
    status: ['active', 'pending', 'error'][i % 3],
    priority: ['high', 'medium', 'low'][i % 3],
    name: `Item ${i + 1}`,
    value: Math.random() * 10000,
    progress: Math.random(),
    updatedAt: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(),
    isArchived: i % 10 === 0
  }));

  return (
    <DataGrid
      columns={columns}
      createRows={largeDataset}
      rowKey="id"
      selectData={setSelectedRows}
      enableVirtualization={true}
      enableCompactStyleMode={true}
      rowHeight={40}
      fontSize={12}
      gridHeight="calc(100vh - 200px)"
      getRowStyle={getRowStyle}
      pageSize={100}
      itemsPerPage={[50, 100, 200, 500]}
    />
  );
}

Example 6: Advanced Features with Cache Management

function AdvancedGrid() {
  const [data, setData] = useState([]);
  const [cacheLoading, setCacheLoading] = useState(false);
  const [selectedRows, setSelectedRows] = useState([]);
  const [visibleRowCount, setVisibleRowCount] = useState(0);

  const refreshData = async () => {
    setCacheLoading(true);
    try {
      const newData = await fetchLatestData();
      setData(newData);
    } catch (error) {
      console.error('Failed to refresh data:', error);
    } finally {
      setCacheLoading(false);
    }
  };

  const handleVisibleRowsChange = (rows) => {
    setVisibleRowCount(rows.length);
    console.log('Visible rows:', rows);
  };

  const exportCustom = () => {
    console.log('Custom export logic');
  };

  const actions = [
    {
      name: 'Process',
      function: (rows) => processSelectedRows(rows),
      tooltip: 'Process selected items',
      color: 'blue',
      icon: 'cog',
      selectionMode: 'multi'
    }
  ];

  const extraActions = [
    {
      function: exportCustom,
      name: 'Custom Export',  // Can be used as fallback for content
      tooltip: 'Export with custom format',
      icon: 'file alternate outline'
    },
    {
      function: () => console.log('Refresh'),
      name: 'Refresh',
      tooltip: 'Refresh data',
      icon: 'redo',
      loading: cacheLoading,  // Props spread directly to Button
      disabled: cacheLoading
    }
  ];

  const columns = [
    { accessorKey: 'id', header: 'ID', type: 'integer' },
    { accessorKey: 'name', header: 'Name', type: 'textTitle' },
    { accessorKey: 'status', header: 'Status', type: 'text' },
    { 
      accessorKey: 'amount',
      accessorFn: (row) => row.amount ?? 0,  // Ensure numeric value
      header: 'Amount',
      type: 'currency'
    },
    { accessorKey: 'createdAt', header: 'Created', type: 'datetime', isDateColumn: true },
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={data}
      rowKey="id"
      selectData={setSelectedRows}
      
      // Actions
      actions={actions}
      extraActions={extraActions}
      
      // Advanced features
      enableGlobalFilter={true}
      globalFilterFn="fuzzy"
      enableColumnFilterModes={true}
      enableFixedHeader={true}
      enableFixedActions={true}
      
      // Cache management
      updateCache={refreshData}
      cacheUpdateText="Refresh data from server"
      cacheUpdating={cacheLoading}
      
      // Callbacks
      onVisibleRowsChange={handleVisibleRowsChange}
      
      // Help
      gridHelper={{
        title: 'Data Grid Help',
        content: (
          <div>
            <h3>Quick Guide</h3>
            <ul>
              <li><strong>Selection:</strong> Click rows to select, use checkboxes for multi-select</li>
              <li><strong>Filtering:</strong> Use column filters to search specific fields</li>
              <li><strong>Global Search:</strong> Search across all columns at once</li>
              <li><strong>Sorting:</strong> Click column headers to sort</li>
              <li><strong>Export:</strong> Use Excel or PDF buttons to export data</li>
              <li><strong>Refresh:</strong> Click cache button to reload latest data</li>
            </ul>
            <p><strong>Currently showing:</strong> {visibleRowCount} rows</p>
          </div>
        )
      }}
      
      // Display
      gridHeight={700}
      pageSize={100}
      itemsPerPage={[50, 100, 200]}
    />
  );
}

Example 7: Disabled Rows and Custom Row Styles

function OrderGrid() {
  const [orders, setOrders] = useState([]);
  const [selected, setSelected] = useState([]);

  // Disable completed and cancelled orders from selection
  const getDisabledRows = () => {
    return orders
      .filter(order => ['completed', 'cancelled'].includes(order.status))
      .map(order => order.orderId);
  };

  const getRowStyle = ({ row }) => {
    const status = row.original.status;
    
    switch (status) {
      case 'pending':
        return { backgroundColor: '#fff3cd' };
      case 'processing':
        return { backgroundColor: '#cfe2ff' };
      case 'completed':
        return { backgroundColor: '#d1e7dd', opacity: 0.7 };
      case 'cancelled':
        return { backgroundColor: '#f8d7da', opacity: 0.7 };
      default:
        return {};
    }
  };

  const columns = [
    { accessorKey: 'orderId', header: 'Order ID', type: 'text' },
    { accessorKey: 'customer', header: 'Customer', type: 'textTitle' },
    { 
      accessorKey: 'total',
      accessorFn: (row) => row.total ?? 0,  // Ensure numeric value
      header: 'Total',
      type: 'currency'
    },
    { accessorKey: 'status', header: 'Status', type: 'text' },
    { accessorKey: 'orderDate', header: 'Order Date', type: 'datetime', isDateColumn: true },
  ];

  return (
    <DataGrid
      columns={columns}
      createRows={orders}
      rowKey="orderId"
      selectData={setSelected}
      disableRows={getDisabledRows()}
      getRowStyle={getRowStyle}
      gridHeight={600}
    />
  );
}

API Reference

Column Definition Object

interface ColumnDefinition {
  // Required
  accessorKey: string;              // Key identifier for the column
  header: string;                   // Column header text
  
  // Data Access (choose one)
  // Option 1: Direct property access (default when no accessorFn)
  // Option 2: Custom accessor function
  accessorFn?: (row: Object) => any; // Function to extract/compute value from row
  
  // Type & Rendering
  type?: string;                    // Cell type for automatic formatting
  Cell?: React.Component;           // Custom cell renderer (receives typeValue)
  cellClass?: string;               // CSS class wrapper for cell content
  
  // Filtering
  enableColumnFilter?: boolean;     // Default: true
  enableColumnFilterModes?: boolean;// Default: true
  filterFn?: string | function;     // Default: 'contains' (or undefined for dates)
  
  // Sorting
  enableSorting?: boolean;          // Default: true
  sortingFn?: string | function;    // Default: 'basic' (or custom for dates)
  isDateColumn?: boolean;           // Special date handling (default: false)
  
  // Display
  enableResizing?: boolean;         // Default: true
  grow?: boolean;                   // Column can grow (default: true)
  enableClickToCopy?: boolean;      // Default: false
  enableColumnActions?: boolean;    // Default: false
  
  // Additional
  locale?: string;                  // Locale for formatting (e.g., 'en-US')
  onlyFlag?: boolean;               // For countryFlag type
  columnDef?: object;               // Additional metadata
}

Action Object

interface ActionObject {
  // Required
  name: string;                     // Button label
  function: (selectedRows: Array, table?: Object) => void; // Click handler
  
  // Display
  tooltip?: string;                 // Hover tooltip
  color?: 'blue' | 'red' | 'green' | 'yellow' | 'orange' | 'black' | 'grey' | 
          'teal' | 'brown' | 'violet' | 'purple' | 'olive' | 'pink';
  icon?: string | React.Element;    // Icon name or element
  
  // Behavior
  selectionMode?: 'single' | 'multi' | 'always';
  confirmMessage?: string | React.Element;
  hasConfirmMessage?: boolean;
  disabled?: boolean;
  visible?: boolean;                // Default: true
  
  // Toggle mode
  toggle?: boolean;
  active?: boolean;
  
  // Other
  key?: string;                     // Unique React key
}

Filter Action Object

interface FilterActionObject {
  // Required
  name: string;                     // Button label
  function: () => void;             // Toggle handler
  state: boolean;                   // Current filter state (true=hidden, false=shown)
  
  // Display
  tooltip?: string;                 // Hover tooltip
  icon?: string | React.Element;    // Icon name or element (default: eye/eye-slash based on state)
  visible?: boolean;                // Show/hide the button (default: true)
  
  // Behavior
  disabled?: boolean;               // Manually disable the button
  key?: string;                     // Unique React key (defaults to name)
}

Extra Action Object

interface ExtraActionObject {
  // Required
  function: () => void;             // Click handler
  
  // Content (at least one required)
  content?: string | React.Element; // Button content/label (falls back to name)
  name?: string;                    // Button label; used when content is not provided
  
  // Display
  tooltip?: string;                 // Hover tooltip
  icon?: string | React.Element;    // Icon name or element
  style?: React.CSSProperties;      // Custom button styles
  visible?: boolean;                // Show/hide the button (default: true)
  
  // Backward compatibility
  propsButton?: object;             // Additional Semantic UI Button props (deprecated - use ...rest instead)
  
  // Flexible prop spreading
  [key: string]: any;               // Any additional props spread directly to Button component
}

ExportActions Component

The ExportActions component handles both Excel and PDF export with a user-facing confirmation modal. It is used internally by DataGrid and driven by the hasExcelExport, hasPdfExport, exportColumns, exportfileName, pdfExportTitle, and pdfExportBrand props.

How it works

  1. Trigger — Clicking the Excel or PDF button opens a modal.
  2. Modal — The user can adjust:
    • File name (both formats)
    • Document title (PDF only)
    • A read-only preview of all columns being exported is shown.
  3. Confirm — Clicking Export generates and downloads the file.

Excel Export

  • Uses xlsx (SheetJS) to create an .xlsx workbook.
  • Column widths are auto-sized based on header and cell content (capped at 60 characters).
  • Row 1 is frozen as a header row.

PDF Export

  • Uses jsPDF + jspdf-autotable.
  • Landscape orientation.
  • Structure (top to bottom):
    1. Logo — Rendered from pdfExportBrand.logoBase64 if provided.
    2. Title — Bold, primary color, left-aligned.
    3. Date — Current date, right-aligned, muted gray.
    4. Table — Header row uses primaryColor background and secondaryColor text. Alternating rows use accentColor.
    5. Page number — Centered footer on every page.

Cell value resolution

For each cell, ExportActions calls the column's Cell renderer with a minimal MRT-compatible context. If the renderer returns a React element, the raw string value is used as fallback. This ensures that type formatters (date, datetime, currency, percentage, htmlText, etc.) produce clean plain-text output in the exported file.

ExportActions Props

| Prop | Type | Required | Default | Description | | ---------------- | --------- | -------- | ----------- | ------------------------------------------------------------------------- | | hasExcelExport | boolean | ✓ | — | Show the Excel export button | | hasPdfExport | boolean | ✓ | — | Show the PDF export button | | rows | Array | ✓ | — | Raw data rows (all of createRows) | | columns | Array | ✓ | — | Already-processed columns from createColumns(exportColumns ?? columns) | | table | object | — | undefined | Optional MRT table instance; enables filter/sort-aware row export | | fileName | string | — | 'data' | Default file name pre-filled in the modal | | exportTitle | string | — | '' | Default document title pre-filled in the modal (PDF only) | | brand | object | — | {} | PDF branding — merged with internal defaults (see pdfExportBrand above) |


Performance Tips

1. Use Virtualization for Large Datasets

// For 1000+ rows
enableVirtualization={true}

2. Optimize Row Height and Compact Mode

// Smaller rows = more visible data
rowHeight={40}
enableCompactStyleMode={true}
fontSize={12}

3. Disable Unused Features

// Reduce overhead by disabling features you don't need
enableDensityToggle={false}
enableFullScreenToggle={false}
enableGlobalFilter={false}
enableColumnFilterModes={false}

4. Limit Initial Page Size

// Don't render too many rows initially
pageSize={50}  // Instead of 150
itemsPerPage={[25, 50, 100]}

5. Pre-select Rows Carefully

// Only include necessary IDs
selectedIds={criticalIds}  // Instead of selecting all rows

6. Optimize Custom Cell Renderers

// Use typeValue when available
const MyCell = ({ typeValue, cell }) => {
  return typeValue || cell.getValue(); // Prefer pre-formatted typeValue
};

// Memoize expensive computations
const ExpensiveCell = React.memo(({ cell }) => {
  const processedValue = useMemo(() => expensiveComputation(cell.getValue()), [cell]);
  return <div>{processedValue}</div>;
});

7. Keep accessorFn Lightweight

// Bad - Complex computation on every render/filter/sort
accessorFn: (row) => {
  return expensiveCalculation(row.data);
}

// Good - Simple, fast operations
accessorFn: (row) => row.data?.value ?? 0

// Better - Pre-process data before passing to grid
const processedData = rawData.map(row => ({
  ...row,
  computedValue: expensiveCalculation(row.data)
}));

8. Use Column Visibility Wisely

// Hide columns that aren't immediately needed
columnVisibilityState={{
  metadata: false,
  internalId: false,
  debugInfo: false
}}

9. Implement Efficient Row Styling

// Keep getRowStyle lightweight
getRowStyle={({ row }) => {
  // Simple conditional - avoid heavy computation
  return row.original.isHighlighted ? { backgroundColor: '#fffacd' } : {};
}}

10. Batch State Updates

// Instead of multiple state updates, batch them
const handleMultipleChanges = () => {
  // Use a single state update with derived values
  setData(prevData => processAndUpdate(prevData));
};

11. Leverage React's Built-in Optimizations

// Use keys properly for subRows
const data = subRowData.map((item, index) => ({
  ...item,
  id: `${parentId}.${index}` // Stable, unique keys
}));

Browser Supp