Skip to content

haydenk/tablekit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TableKit

A lightweight, framework-agnostic data table library built with TypeScript. TableKit has zero runtime dependencies and is designed around a plugin architecture — use only what you need.

Features

  • Zero dependencies, plain TypeScript/DOM
  • Plugin-based: filter, pagination, selection, column visibility
  • Multiple data sources: static arrays, AJAX, async functions
  • Multi-column sorting (click + Shift-click)
  • Custom cell renderers and sort comparators
  • CSS custom property theming
  • Full TypeScript types

Installation

bun add @tablekit/core
# or
npm install @tablekit/core

Quick Start

import { createTable, withFilter, withPagination, withSelection } from '@tablekit/core'
import '@tablekit/core/dist/tablekit.css'

const table = createTable('#my-table', {
  columns: [
    { key: 'name',  title: 'Name',  type: 'string', sortable: true },
    { key: 'email', title: 'Email', type: 'string', sortable: true },
    { key: 'score', title: 'Score', type: 'number', sortable: true },
  ],
  data: [
    { name: 'Alice', email: 'alice@example.com', score: 95 },
    { name: 'Bob',   email: 'bob@example.com',   score: 82 },
  ],
  plugins: [
    withFilter({ debounce: 200 }),
    withPagination({ pageSize: 25, pageSizes: [10, 25, 50], showInfo: true }),
    withSelection({ mode: 'multi' }),
  ],
})

Data Sources

TableKit accepts three data source formats:

// Static array
data: [{ id: 1, name: 'Alice' }]

// AJAX
data: {
  url: '/api/users',
  method: 'GET',
  headers: { Authorization: 'Bearer token' },
  dataSrc: (response) => response.data, // transform response
}

// Async function
data: async () => {
  const res = await fetch('/api/users')
  return res.json()
}

Column Definition

interface ColumnDef {
  key: string
  title: string
  type?: 'string' | 'number' | 'date' | 'boolean' | 'custom'
  width?: number | string
  minWidth?: number
  maxWidth?: number
  visible?: boolean
  sortable?: boolean
  filterable?: boolean
  resizable?: boolean
  pinned?: 'left' | 'right' | false
  className?: string

  // Custom cell renderer — return an HTMLElement or HTML string
  render?: (value: CellValue, row: Row, col: ColumnDef) => HTMLElement | string

  // Custom sort comparator
  compare?: (a: CellValue, b: CellValue) => number
}

Custom Cell Renderer Example

{
  key: 'status',
  title: 'Status',
  render: (val) => {
    const badge = document.createElement('span')
    badge.className = `badge badge--${val}`
    badge.textContent = String(val)
    return badge
  },
}

Plugins

withFilter(options?)

Adds a global search input above the table.

Option Type Default Description
debounce number 250 Input debounce in milliseconds
placeholder string 'Search…' Input placeholder text
withFilter({ debounce: 200, placeholder: 'Search users…' })

withPagination(options?)

Adds a pagination bar below the table.

Option Type Default Description
pageSize number 25 Initial rows per page
pageSizes number[] Show a rows-per-page dropdown
showInfo boolean true Show "1–25 of 120" info text
withPagination({ pageSize: 15, pageSizes: [10, 15, 25, 50], showInfo: true })

withSelection(options?)

Enables row selection.

Option Type Default Description
mode SelectionMode 'multi' 'single', 'multi', 'cell', 'column', or false
checkboxColumn boolean false Reserved — checkbox column support

Multi-select: plain click selects a single row; Ctrl/Cmd or Shift click toggles/adds rows.

withSelection({ mode: 'multi' })

withColumnVisibility(options?)

Adds a "Columns" dropdown to show/hide columns.

Option Type Default Description
showToggle boolean true Render the toggle button
withColumnVisibility({ showToggle: true })

Events

Subscribe to table events with table.on(). The unsubscribe function is returned.

const unsub = table.on('selection:change', ({ selection }) => {
  console.log('Selected rows:', [...selection.rows])
})

// Later:
unsub()
Event Payload
data:loading {}
data:loaded { rows: Row[] }
sort:change { sort: SortEntry[] }
filter:change { filter: FilterState }
page:change { pagination: PaginationState }
selection:change { selection: SelectionState }
column:visibility { key: string; visible: boolean }
column:resize { key: string; width: number }
column:reorder { from: number; to: number }
row:reorder { from: number; to: number }
render:complete {}
destroy {}

API

const table = createTable(container, options)

table.state           // Readonly current state
table.render()        // Force re-render
table.setState(patch) // Patch state and re-render manually
table.destroy()       // Tear down table and all plugins
table.getContainer()  // Returns the wrapper HTMLElement
table.getTableEl()    // Returns the <table> HTMLTableElement
table.on(event, fn)   // Subscribe to an event, returns unsubscribe fn
table.off(event, fn)  // Unsubscribe from an event
table.emit(event, payload) // Emit an event

Theming

TableKit uses CSS custom properties. Override them on the container or any ancestor:

#my-table {
  --tk-color-accent:       #8b5cf6;
  --tk-color-accent-hover: #7c3aed;
  --tk-color-accent-light: #ede9fe;
  --tk-color-bg-selected:  #f5f3ff;
}

Writing a Custom Plugin

A plugin is any object that implements TablePlugin:

import type { TablePlugin, TableCore } from '@tablekit/core'

function withMyPlugin(): TablePlugin {
  let table: TableCore

  return {
    name: 'my-plugin',
    install(t) {
      table = t
      t.on('data:loaded', ({ rows }) => {
        console.log(`Loaded ${rows.length} rows`)
      })
    },
    destroy() {
      // cleanup
    },
  }
}

Pass it in the plugins array:

createTable('#table', {
  columns: [...],
  data: [...],
  plugins: [withMyPlugin()],
})

Development

# Install dependencies
bun install

# Start dev server with playground
bun run dev

# Build library
bun run build

# Type check
bun run typecheck

The playground is available at playground/index.html and demonstrates all built-in plugins together.

License

GPL-3.0

About

Lightweight, zero-dependency TypeScript data table library with a plugin architecture — filter, pagination, sorting, selection, and column visibility out of the box.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors