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

@mehdashti/tables

v1.2.0

Published

Enterprise-grade data table components for Smart Platform

Downloads

471

Readme

@mehdashti/tables

Enterprise-grade data tables with TanStack Table v8 for Smart Platform.

Features

Core Table Features

  • Powerful Sorting: Multi-column sorting with custom sort functions
  • Advanced Filtering: Filter Builder with complex AND/OR conditions
  • Pagination: Both client-side and server-side pagination support
  • Row Selection: Single and multi-row selection with bulk actions
  • Column Management: Dynamic show/hide with mobile-responsive defaults
  • Type Safe: Full TypeScript support with strict types
  • Customizable: Custom cell renderers and formatters
  • Loading States: Built-in loading and empty state handling

Enterprise Features (Phase 2)

  • Bulk Actions: Toolbar with actions for selected rows (delete, export, archive, etc.)
  • Data Export: Export to CSV or Excel with customizable columns
  • Aggregations: Summary row with sum, average, min, max calculations
  • Inline Editing: Edit cells directly with validation and auto-save
  • Row Actions: Edit/Cancel/Save actions for row-level editing

Advanced Features (Phase 5)

  • Filter Builder: Visual query builder with multiple operators and conditions
  • Filter Chips: Display active filters as removable chips
  • Saved Filters: Save and manage filter presets with defaults
  • Mobile Card View: Responsive card layout for mobile devices
  • Adaptive Columns: Auto-hide columns on mobile with visibility toggle

Installation

pnpm add @mehdashti/tables

Usage

Basic Table

import { DataTable } from '@mehdashti/tables'
import { ColumnDef } from '@tanstack/react-table'

interface User {
  id: string
  name: string
  email: string
  role: string
}

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: 'Name',
  },
  {
    accessorKey: 'email',
    header: 'Email',
  },
  {
    accessorKey: 'role',
    header: 'Role',
  },
]

function UserTable() {
  const data: User[] = [
    { id: '1', name: 'John Doe', email: '[email protected]', role: 'Admin' },
    { id: '2', name: 'Jane Smith', email: '[email protected]', role: 'User' },
  ]

  return (
    <DataTable
      columns={columns}
      data={data}
      pagination
      sorting
    />
  )
}

With Filtering

<DataTable
  columns={columns}
  data={data}
  filtering
  globalFilter
  placeholder="Search users..."
/>

With Row Selection

function UserTable() {
  const [rowSelection, setRowSelection] = useState({})

  return (
    <DataTable
      columns={columns}
      data={data}
      rowSelection
      onRowSelectionChange={setRowSelection}
    />
  )
}

Server-Side Pagination

function UserTable() {
  const [pagination, setPagination] = useState({
    pageIndex: 0,
    pageSize: 10,
  })

  const { data, isLoading } = useQuery({
    queryKey: ['users', pagination],
    queryFn: () => fetchUsers(pagination),
  })

  return (
    <DataTable
      columns={columns}
      data={data?.items ?? []}
      pagination
      pageCount={data?.totalPages}
      onPaginationChange={setPagination}
      isLoading={isLoading}
      manualPagination
    />
  )
}

Column Helpers

Utility functions for common column types:

Sortable Header

import { createSortableHeader } from '@mehdashti/tables'

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: ({ column }) => createSortableHeader(column, 'Name'),
  },
]

Selection Column

import { createSelectionColumn } from '@mehdashti/tables'

const columns = [
  createSelectionColumn<User>(),
  // ... other columns
]

Date Column

import { createDateColumn } from '@mehdashti/tables'

const columns = [
  createDateColumn<User>('createdAt', 'Created', {
    format: 'MMM dd, yyyy',
  }),
]

Badge Column

import { createBadgeColumn } from '@mehdashti/tables'

const columns = [
  createBadgeColumn<User>('status', 'Status', {
    active: 'success',
    inactive: 'secondary',
    pending: 'warning',
  }),
]

Actions Column

import { createActionsColumn } from '@mehdashti/tables'

const columns = [
  createActionsColumn<User>({
    onEdit: (user) => console.log('Edit', user),
    onDelete: (user) => console.log('Delete', user),
    onView: (user) => console.log('View', user),
  }),
]

API

DataTable Props

interface DataTableProps<TData> {
  columns: ColumnDef<TData>[]
  data: TData[]

  // Features
  pagination?: boolean
  sorting?: boolean
  filtering?: boolean
  rowSelection?: boolean
  globalFilter?: boolean

  // Pagination
  pageSize?: number
  pageCount?: number
  onPaginationChange?: (updater: Updater<PaginationState>) => void
  manualPagination?: boolean

  // Sorting
  onSortingChange?: (updater: Updater<SortingState>) => void
  manualSorting?: boolean

  // Filtering
  onFilteringChange?: (updater: Updater<ColumnFiltersState>) => void
  onGlobalFilterChange?: (value: string) => void
  manualFiltering?: boolean

  // Selection
  onRowSelectionChange?: (updater: Updater<RowSelectionState>) => void

  // UI
  isLoading?: boolean
  emptyMessage?: string
  placeholder?: string
  showColumnVisibility?: boolean

  // Styling
  className?: string
}

Enterprise Features

Bulk Actions

Handle multiple rows with bulk action toolbar.

import { DataTable, BulkActionsToolbar } from '@mehdashti/tables'

function UserTable() {
  const [rowSelection, setRowSelection] = useState({})

  const handleDelete = (selectedRows: User[]) => {
    console.log('Delete', selectedRows)
  }

  const handleExport = (selectedRows: User[]) => {
    console.log('Export', selectedRows)
  }

  return (
    <>
      <BulkActionsToolbar
        selectedCount={Object.keys(rowSelection).length}
        onDelete={handleDelete}
        onExport={handleExport}
        actions={[
          { label: 'Archive', onClick: handleArchive },
          { label: 'Tag', onClick: handleTag },
        ]}
      />
      <DataTable
        columns={columns}
        data={data}
        rowSelection
        onRowSelectionChange={setRowSelection}
      />
    </>
  )
}

Data Export

Export table data to CSV or Excel.

import { ExportButton } from '@mehdashti/tables'

<ExportButton
  data={data}
  filename="users"
  format="csv"
  columns={['name', 'email', 'role']}
/>

// Or export to Excel
<ExportButton
  data={data}
  filename="users"
  format="xlsx"
/>

Aggregation Row

Show summary calculations at the bottom of the table.

import { AggregationRow } from '@mehdashti/tables'

<AggregationRow
  columns={[
    { field: 'revenue', type: 'sum', label: 'Total Revenue' },
    { field: 'orders', type: 'count', label: 'Total Orders' },
    { field: 'rating', type: 'avg', label: 'Avg Rating' },
  ]}
  data={data}
/>

Inline Editing

Edit cells directly with validation.

import { EditableCell, RowEditActions } from '@mehdashti/tables'

const columns = [
  {
    accessorKey: 'name',
    header: 'Name',
    cell: ({ row, getValue }) => (
      <EditableCell
        value={getValue()}
        onSave={(value) => handleSave(row.id, 'name', value)}
        isEditing={row.getIsEditing()}
      />
    ),
  },
  {
    id: 'actions',
    cell: ({ row }) => (
      <RowEditActions
        isEditing={row.getIsEditing()}
        onEdit={() => row.toggleEditing()}
        onSave={() => handleRowSave(row)}
        onCancel={() => row.toggleEditing()}
      />
    ),
  },
]

Advanced Features

Filter Builder

Build complex filter queries with AND/OR logic.

import { FilterBuilder, type FilterGroup } from '@mehdashti/tables'

function TableWithFilters() {
  const [filter, setFilter] = useState<FilterGroup>({
    id: '1',
    logic: 'AND',
    conditions: [],
  })

  return (
    <FilterBuilder
      fields={[
        { name: 'name', label: 'Name', type: 'string' },
        { name: 'age', label: 'Age', type: 'number' },
        { name: 'status', label: 'Status', type: 'string' },
      ]}
      value={filter}
      onChange={setFilter}
    />
  )
}

Filter Chips

Display and manage active filters.

import { FilterChips } from '@mehdashti/tables'

<FilterChips
  filter={currentFilter}
  onRemove={(conditionId) => handleRemoveFilter(conditionId)}
  onClear={() => setFilter({ id: '1', logic: 'AND', conditions: [] })}
  fieldLabels={{
    name: 'Full Name',
    email: 'Email Address',
    status: 'Account Status',
  }}
/>

Saved Filters

Save and reuse filter presets.

import { SavedFilters, type SavedFilter } from '@mehdashti/tables'

function TableWithSavedFilters() {
  const [savedFilters, setSavedFilters] = useState<SavedFilter[]>([])
  const [currentFilter, setCurrentFilter] = useState<FilterGroup>(...)

  return (
    <SavedFilters
      filters={savedFilters}
      currentFilter={currentFilter}
      onApply={(filter) => setCurrentFilter(filter.filter)}
      onSave={(name) => {
        const newFilter = {
          id: generateId(),
          name,
          filter: currentFilter,
          createdAt: new Date(),
        }
        setSavedFilters([...savedFilters, newFilter])
      }}
      onDelete={(id) => {
        setSavedFilters(savedFilters.filter((f) => f.id !== id))
      }}
      onSetDefault={(id) => {
        setSavedFilters(
          savedFilters.map((f) => ({
            ...f,
            isDefault: f.id === id,
          }))
        )
      }}
    />
  )
}

Mobile Card View

Responsive card layout for mobile devices.

import { MobileCardView, type MobileCardField } from '@mehdashti/tables'

const fields: MobileCardField<User>[] = [
  {
    accessorKey: 'name',
    label: 'Name',
    primary: true, // Show as card title
  },
  {
    accessorKey: 'email',
    label: 'Email',
  },
  {
    accessorKey: 'role',
    label: 'Role',
    render: (value) => <Badge>{value}</Badge>,
  },
  {
    accessorKey: 'internalId',
    label: 'Internal ID',
    hideOnMobile: true, // Hide on mobile
  },
]

<MobileCardView
  data={users}
  fields={fields}
  onCardClick={(user) => navigate(`/users/${user.id}`)}
  isLoading={isLoading}
  emptyMessage="No users found"
/>

Column Visibility Toggle

Manage column visibility with mobile defaults.

import { ColumnVisibilityToggle, type ColumnConfig } from '@mehdashti/tables'

const columns: ColumnConfig[] = [
  { id: 'name', label: 'Name', enableHiding: false },
  { id: 'email', label: 'Email' },
  { id: 'phone', label: 'Phone', hideOnMobile: true },
  { id: 'address', label: 'Address', hideOnMobile: true },
  { id: 'status', label: 'Status' },
]

<ColumnVisibilityToggle
  columns={columns}
  visibility={columnVisibility}
  onChange={setColumnVisibility}
/>

API Reference

Components

  • DataTable - Main table component with all features
  • BulkActionsToolbar - Toolbar for bulk operations
  • ExportButton - Export data to CSV/Excel
  • AggregationRow - Summary calculations row
  • EditableCell - Inline editable cell
  • EditableSelectCell - Inline editable select cell
  • RowEditActions - Edit/Save/Cancel actions for rows
  • FilterBuilder - Visual query builder
  • FilterChips - Active filter display
  • SavedFilters - Filter preset management
  • MobileCardView - Mobile-optimized card layout
  • ColumnVisibilityToggle - Column visibility control

Column Helpers

  • createSortableHeader - Sortable column header
  • createSelectionColumn - Checkbox selection column
  • createDateColumn - Formatted date column
  • createBadgeColumn - Badge status column
  • createActionsColumn - Row actions dropdown

Types

export type FilterOperator =
  | "equals" | "notEquals"
  | "contains" | "notContains"
  | "startsWith" | "endsWith"
  | "greaterThan" | "lessThan"
  | "greaterThanOrEqual" | "lessThanOrEqual"
  | "between" | "in" | "notIn"
  | "isEmpty" | "isNotEmpty"

export type FilterCondition = {
  id: string
  field: string
  operator: FilterOperator
  value: any
  type?: "string" | "number" | "date" | "boolean"
}

export type FilterGroup = {
  id: string
  logic: "AND" | "OR"
  conditions: (FilterCondition | FilterGroup)[]
}

export interface MobileCardField<TData> {
  accessorKey: keyof TData
  label: string
  render?: (value: any, row: TData) => React.ReactNode
  primary?: boolean
  hideOnMobile?: boolean
}

export interface ColumnConfig {
  id: string
  label: string
  hideOnMobile?: boolean
  enableHiding?: boolean
}

Examples

See Storybook stories for interactive examples.

License

MIT