Components
DataTable

DataTable

The DataTable component is an advanced table with built-in search, filtering, sorting, and pagination. It's built on top of the Table component and provides enhanced data management capabilities.

Import

import { DataTable } from '@nostromo/ui-core'
// or
import { DataTable } from '@nostromo/ui-core/data-table'

Usage

import { DataTable } from '@nostromo/ui-core'
 
const data = [
  { id: 1, name: 'John Doe', email: 'john@example.com', department: 'Engineering' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', department: 'Marketing' }
]
 
const columns = [
  { key: 'name', title: 'Name', dataIndex: 'name', sortable: true },
  { key: 'email', title: 'Email', dataIndex: 'email' },
  { key: 'department', title: 'Department', dataIndex: 'department', sortable: true }
]
 
export default function Example() {
  return (
    <DataTable
      data={data}
      columns={columns}
      searchable={true}
      showPagination={true}
    />
  )
}

Live Examples

Live Example
☀️
Copy
Storybook →
View Code
import { DataTable } from '@nostromo/ui-core' const data = [ { id: 1, name: 'John Doe', email: 'john@example.com', age: 28, department: 'Engineering', status: 'Active' }, { id: 2, name: 'Jane Smith', email: 'jane@example.com', age: 32, department: 'Marketing', status: 'Active' }, { id: 3, name: 'Bob Johnson', email: 'bob@example.com', age: 45, department: 'Sales', status: 'Inactive' }, { id: 4, name: 'Alice Brown', email: 'alice@example.com', age: 29, department: 'Engineering', status: 'Active' } ] const columns = [...
Live Example
☀️
Copy
Storybook →
View Code
import { DataTable } from '@nostromo/ui-core' const data = [ { id: 1, name: 'John Doe', email: 'john@example.com', department: 'Engineering', status: 'Active' }, { id: 2, name: 'Jane Smith', email: 'jane@example.com', department: 'Marketing', status: 'Active' }, { id: 3, name: 'Bob Johnson', email: 'bob@example.com', department: 'Sales', status: 'Inactive' }, { id: 4, name: 'Alice Brown', email: 'alice@example.com', department: 'Engineering', status: 'Active' } ] const columns = [...

Features

Search

  • Global search across multiple columns
  • Custom search keys to specify which columns to search
  • Real-time filtering as you type
  • Search callback for custom handling
  • Controlled mode - Use searchTerm and onSearchTermChange for server-side search

Filtering

  • Column filters with multiple filter types (text, select, number, date, boolean)
  • Multiple filters can be applied simultaneously
  • Custom filter functions for advanced filtering logic
  • Clear filters button to reset all filters
  • Controlled mode - Use columnFilters and onColumnFiltersChange for server-side filtering

Sorting

  • Column sorting with ascending/descending order
  • Default sort column and direction
  • Controlled mode - Use sortColumn, sortDirection, and onSortChange for server-side sorting
  • Sort indicators in column headers

Pagination

  • Client-side pagination - Automatic pagination of data (default)
  • Server-side pagination - Controlled mode with currentPage, pageSize, onPageChange, onPageSizeChange, and totalItems
  • Page size options (10, 20, 50, 100 by default)
  • Results summary showing current range and total
  • Can be disabled for small datasets

Props

PropTypeDefaultRequiredDescription
dataT[]-YesArray of data objects to display
columnsTableColumn<T>[]-YesColumn definitions (see TableColumn interface)
searchablebooleantrueNoEnable global search functionality
searchPlaceholderstring"Search..."NoPlaceholder text for search input
searchKeysArray<keyof T | string>undefinedNoSpecific columns to search (defaults to all columns)
onSearch(searchTerm: string, filteredData: T[]) => voidundefinedNoCallback when search term changes
searchTermstringundefinedNoControlled search term (for server-side search)
onSearchTermChange(searchTerm: string) => voidundefinedNoCallback when search term changes (controlled mode)
filterablebooleanfalseNoEnable column filtering
filtersColumnFilter<T>[][]NoFilter definitions (see ColumnFilter interface)
onFilter(filters: Record<string, unknown>, filteredData: T[]) => voidundefinedNoCallback when filters change
columnFiltersRecord<string, unknown>undefinedNoControlled column filters (for server-side filtering)
onColumnFiltersChange(filters: Record<string, unknown>) => voidundefinedNoCallback when filters change (controlled mode)
defaultSortColumnstringundefinedNoDefault column to sort by
defaultSortDirection"asc" | "desc""asc"NoDefault sort direction
sortColumnstringundefinedNoControlled sort column (for server-side sorting)
sortDirection"asc" | "desc"undefinedNoControlled sort direction (for server-side sorting)
onSortChange(column: string, direction: "asc" | "desc") => voidundefinedNoCallback when sort changes (controlled mode)
defaultPageSizenumber10NoDefault number of items per page
currentPagenumberundefinedNoControlled current page (for server-side pagination)
pageSizenumberundefinedNoControlled page size (for server-side pagination)
onPageChange(page: number) => voidundefinedNoCallback when page changes (controlled mode)
onPageSizeChange(size: number) => voidundefinedNoCallback when page size changes (controlled mode)
totalItemsnumberundefinedNoTotal number of items (required for server-side pagination)
pageSizeOptionsnumber[][10, 20, 50, 100]NoAvailable page size options
showPaginationbooleantrueNoShow pagination controls
showSearchbooleantrueNoShow search bar
showFiltersbooleantrueNoShow filter controls
rowKeykeyof T | ((record: T) => string | number)"id"NoKey to identify rows
emptyTextstring"No data found"NoText to show when no data
classNamestringundefinedNoAdditional CSS classes
variant"default" | "striped" | "bordered" | "hover" | "elevated" | "interactive""default"NoTable visual variant
size"sm" | "md" | "lg""md"NoTable size
loadingbooleanfalseNoShow loading state
captionstringundefinedNoTable caption (for accessibility)
onRowClick(record: T, index: number) => voidundefinedNoCallback when row is clicked
selectionSelectionConfig<T>undefinedNoRow selection configuration (see Table component)

ColumnFilter Interface

interface ColumnFilter<T = Record<string, unknown>> {
  key: string;                    // Column key to filter
  type: 'text' | 'select' | 'number' | 'date' | 'boolean';
  options?: Array<{                // For 'select' type
    label: string;
    value: string | number;
  }>;
  placeholder?: string;            // Placeholder for filter input
  filterFn?: (value: unknown, record: T) => boolean;  // Custom filter function
}

Examples

Basic DataTable with Search

<DataTable
  data={employees}
  columns={columns}
  searchable={true}
  searchPlaceholder="Search employees..."
/>

DataTable with Filters

<DataTable
  data={employees}
  columns={columns}
  searchable={true}
  filterable={true}
  filters={[
    {
      key: 'department',
      type: 'select',
      options: [
        { label: 'Engineering', value: 'Engineering' },
        { label: 'Marketing', value: 'Marketing' }
      ]
    },
    {
      key: 'status',
      type: 'select',
      options: [
        { label: 'Active', value: 'Active' },
        { label: 'Inactive', value: 'Inactive' }
      ]
    }
  ]}
/>

DataTable with Custom Search Keys

<DataTable
  data={employees}
  columns={columns}
  searchable={true}
  searchKeys={['name', 'email']}  // Only search in name and email columns
  searchPlaceholder="Search by name or email..."
/>

DataTable with Default Sort

<DataTable
  data={employees}
  columns={columns}
  defaultSortColumn="name"
  defaultSortDirection="asc"
/>

DataTable without Pagination

<DataTable
  data={employees}
  columns={columns}
  searchable={true}
  showPagination={false}  // Show all results
/>

DataTable with Server-Side Pagination (Controlled Mode)

import { useState } from 'react'
import { DataTable } from '@nostromo/ui-core'
 
export default function ServerSideDataTable() {
  const [currentPage, setCurrentPage] = useState(1)
  const [pageSize, setPageSize] = useState(10)
  const [sortColumn, setSortColumn] = useState('name')
  const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc')
  const [searchTerm, setSearchTerm] = useState('')
  const [totalItems, setTotalItems] = useState(0)
 
  // Fetch data from server based on current state
  const fetchData = async () => {
    const response = await fetch(`/api/employees?page=${currentPage}&pageSize=${pageSize}&sort=${sortColumn}&direction=${sortDirection}&search=${searchTerm}`)
    const { data, total } = await response.json()
    setTotalItems(total)
    return data
  }
 
  return (
    <DataTable
      data={data}
      columns={columns}
      // Controlled props for server-side operations
      currentPage={currentPage}
      pageSize={pageSize}
      totalItems={totalItems}
      onPageChange={setCurrentPage}
      onPageSizeChange={setPageSize}
      sortColumn={sortColumn}
      sortDirection={sortDirection}
      onSortChange={(col, dir) => {
        setSortColumn(col)
        setSortDirection(dir)
      }}
      searchTerm={searchTerm}
      onSearchTermChange={setSearchTerm}
    />
  )
}

Accessibility

  • WCAG 2.1 AA compliant
  • Keyboard navigation for all interactive elements
  • ARIA labels for search and filter inputs
  • Screen reader support with proper table structure
  • Focus management for pagination controls

Do's and Don'ts

✅ Do

  • Use DataTable for large datasets that need search/filter
  • Provide meaningful column titles
  • Use appropriate filter types for each column
  • Set reasonable default page sizes
  • Include rowKey for proper row identification

❌ Don't

  • Use DataTable for simple static tables (use Table instead)
  • Overload with too many filters
  • Use very large page sizes (>100)
  • Forget to handle empty states
  • Use without pagination for large datasets

Related Components

  • Table - Basic table component
  • Input - Used for search input
  • Select - Used for filter dropdowns
  • Pagination - Used for pagination controls