Skip to content

herolabid/LiteTable.js

Repository files navigation

🚀 LiteTable.js

The DataTables alternative you've been waiting for - Super lightweight, framework-agnostic table library under 26KB

npm version Bundle Size License: MIT TypeScript Package Manager

Buy Me A Coffee


✨ Why LiteTable.js?

Feature LiteTable.js DataTables TanStack Table AG Grid Community
Bundle Size ~8-15KB ~150KB + jQuery (30KB) ~15KB ~200KB+
TypeScript ✅ Native ✅ Native
Dependencies ✅ Zero ❌ jQuery ✅ Zero ✅ Zero
Framework Support ✅ React, Vue, Vanilla ⚠️ Wrappers ✅ Multi-framework ✅ Multi-framework
Headless ✅ Yes ❌ No ✅ Yes ❌ No
Learning Curve ✅ Easy ⚠️ Medium ⚠️ Medium ❌ Steep
Performance (10k rows) ✅ Excellent ⚠️ Good ✅ Excellent ✅ Excellent

📦 Installation

LiteTable.js supports npm, pnpm, yarn, and bun:

# npm
npm install @herolabid/litetable-core @herolabid/litetable-react

# pnpm
pnpm add @herolabid/litetable-core @herolabid/litetable-react

# yarn
yarn add @herolabid/litetable-core @herolabid/litetable-react

# bun
bun add @herolabid/litetable-core @herolabid/litetable-react

Packages:

  • @herolabid/litetable-core - Framework-agnostic core (~8KB)
  • @herolabid/litetable-react - React adapter (~1KB)
  • @herolabid/litetable-vue - Vue adapter (~1KB)

Total bundle size:

  • React: ~9KB (core + react)
  • Vue: ~9KB (core + vue)
  • Vanilla: ~8KB (core only)

📖 Full Installation Guide - CDN, troubleshooting, and more


🎯 Features

Core Features (Included in 8KB!)

  • Sorting - Single & multi-column, custom sort functions
  • Filtering - Global search with custom filter logic
  • Pagination - Client-side pagination with page size options
  • Column Control - Show/hide columns dynamically
  • TypeScript - Full type safety with generics
  • Event System - Subscribe to table state changes
  • Immutable State - Predictable state management

Performance

  • 🚀 Sub-millisecond operations for < 100 rows
  • 🚀 O(n log n) sorting with native sort
  • 🚀 O(n) filtering with early returns
  • 🚀 O(1) pagination with array slicing
  • 🚀 Handles 10,000+ rows smoothly

Developer Experience

  • 🧹 Clean API - Intuitive, consistent methods
  • 📘 Full TypeScript - IntelliSense everywhere
  • 🎨 Headless - Complete styling freedom
  • 🔧 Framework Adapters - Native hooks/composables
  • 📚 Well Documented - Clear examples & API docs

🚀 Quick Start

React

npm install @herolabid/litetable-core @herolabid/litetable-react
import { useLiteTable } from '@herolabid/litetable-react'

function UserTable() {
  const table = useLiteTable({
    data: users,
    columns: [
      { id: 'name', header: 'Name', sortable: true },
      { id: 'email', header: 'Email', sortable: true },
      { id: 'role', header: 'Role' }
    ],
    pagination: { page: 1, pageSize: 10 }
  })

  return (
    <div>
      <input
        type="search"
        onChange={(e) => table.search(e.target.value)}
        placeholder="Search..."
      />

      <table>
        <thead>
          <tr>
            {table.visibleColumns.map(col => (
              <th
                key={col.id}
                onClick={() => col.sortable && table.sortBy(col.id)}
              >
                {col.header}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {table.rows.map(row => (
            <tr key={row.id}>
              {table.visibleColumns.map(col => (
                <td key={col.id}>{row[col.id]}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>

      {table.paginationState && (
        <div>
          <button onClick={table.prevPage}>Previous</button>
          <span>Page {table.paginationState.page}</span>
          <button onClick={table.nextPage}>Next</button>
        </div>
      )}
    </div>
  )
}

Vue 3

npm install @herolabid/litetable-core @herolabid/litetable-vue
<script setup lang="ts">
import { useLiteTable } from '@herolabid/litetable-vue'

const table = useLiteTable({
  data: users,
  columns: [
    { id: 'name', header: 'Name', sortable: true },
    { id: 'email', header: 'Email', sortable: true },
    { id: 'role', header: 'Role' }
  ],
  pagination: { page: 1, pageSize: 10 }
})
</script>

<template>
  <div>
    <input
      type="search"
      @input="table.search($event.target.value)"
      placeholder="Search..."
    />

    <table>
      <thead>
        <tr>
          <th
            v-for="col in table.visibleColumns.value"
            :key="col.id"
            @click="col.sortable && table.sortBy(col.id)"
          >
            {{ col.header }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="row in table.rows.value" :key="row.id">
          <td v-for="col in table.visibleColumns.value" :key="col.id">
            {{ row[col.id] }}
          </td>
        </tr>
      </tbody>
    </table>

    <div v-if="table.paginationState.value">
      <button @click="table.prevPage">Previous</button>
      <span>Page {{ table.paginationState.value.page }}</span>
      <button @click="table.nextPage">Next</button>
    </div>
  </div>
</template>

Vanilla JS

npm install @herolabid/litetable-core @litetable/vanilla
import { createLiteTable } from '@litetable/vanilla'

const table = createLiteTable(document.getElementById('table'), {
  data: users,
  columns: [
    { id: 'name', header: 'Name', sortable: true },
    { id: 'email', header: 'Email', sortable: true }
  ]
})

// Search
document.getElementById('search').addEventListener('input', (e) => {
  table.search(e.target.value)
})

📖 Documentation

Core Concepts

1. Headless Architecture

LiteTable.js is headless - it manages logic & state, you control the UI:

// ✅ Use your own markup
<table className="my-custom-table">
  <thead>...</thead>
</table>

// ✅ Use any CSS framework
<table className="table table-striped">  {/* Bootstrap */}
<table className="min-w-full divide-y">  {/* Tailwind */}
<table className="my-table">             {/* Your CSS */}

2. Type Safety

Full TypeScript support with generics:

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

// Type-safe columns
const table = useLiteTable<User>({
  data: users,
  columns: [
    {
      id: 'name', // ✅ Autocomplete from User type
      header: 'Name',
      accessor: (row) => row.name // ✅ row is typed as User
    }
  ]
})

// Type-safe rows
table.rows.map(row => {
  row.name  // ✅ TypeScript knows this exists
  row.invalid // ❌ TypeScript error
})

3. Custom Rendering

Use cell function for custom rendering:

{
  id: 'status',
  header: 'Status',
  cell: (value, row) => (
    <span className={`badge badge-${value}`}>
      {value}
    </span>
  )
}

4. Event System

Subscribe to table updates:

table.tableInstance.on('sort', (state) => {
  console.log('Sorted:', state.sortState)
})

table.tableInstance.on('search', (state) => {
  console.log('Searched:', state.searchTerm)
})

🎨 Styling

LiteTable.js is unstyled by default. Choose your approach:

Option 1: Your Own CSS

.my-table {
  border-collapse: collapse;
  width: 100%;
}

.my-table th {
  background: #f3f4f6;
  padding: 12px;
  text-align: left;
}

Option 2: Tailwind CSS

<table className="min-w-full divide-y divide-gray-200">
  <thead className="bg-gray-50">
    <th className="px-6 py-3 text-left">Name</th>
  </thead>
</table>

Option 3: CSS Framework (Bootstrap, etc.)

<table className="table table-striped table-hover">
  <thead>...</thead>
</table>

⚡ Performance

Benchmarks (10,000 rows)

Operation Time Complexity
Init table ~5ms O(n)
Sort ~15ms O(n log n)
Filter ~8ms O(n)
Paginate <1ms O(1)
Combined (sort+filter+page) ~25ms O(n log n)

Run benchmarks:

pnpm bench

Optimization Tips

  1. Use debounced search for search inputs:
import { useDebouncedSearch } from '@herolabid/litetable-react'

const [searchValue, setSearch] = useDebouncedSearch(table.search, 300)
  1. Pagination for large datasets:
pagination: {
  page: 1,
  pageSize: 25  // Render only 25 rows
}
  1. Virtual scrolling (future module) for 100k+ rows

🏗️ Project Structure

litetable/
├── packages/
│   ├── core/              # Framework-agnostic logic (~8KB)
│   ├── react/             # React adapter (~3KB)
│   ├── vue/               # Vue adapter (~3KB)
│   └── vanilla/           # Vanilla JS adapter (~2KB)
├── examples/
│   ├── react-example/     # React demo app
│   └── vue-example/       # Vue demo app
├── benchmarks/            # Performance benchmarks
└── docs/                  # Documentation

🤝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Development Setup

# Clone repo
git clone git@github.com:herolabid/LiteTable.js.git
cd LiteTable.js

# Install dependencies (requires pnpm)
pnpm install

# Build all packages
pnpm build

# Run benchmarks
pnpm bench

# Run examples
cd examples/react-example
pnpm dev

📝 License

MIT © Irfan Arsyad


🙏 Acknowledgments

Inspired by:


📊 Comparison

vs DataTables

LiteTable.js DataTables
Size 8-15KB ~180KB (with jQuery)
TypeScript ✅ Native
Modern frameworks ✅ First-class ⚠️ Wrappers
jQuery dependency ✅ Zero ❌ Required
Headless ✅ Yes ❌ No

vs TanStack Table

LiteTable.js TanStack Table
Size ~11KB ~15KB
Learning curve ✅ Easy ⚠️ Medium
API simplicity ✅ Simple ⚠️ Complex
Features ⚠️ Core only ✅ Advanced
Performance ✅ Excellent ✅ Excellent

Use LiteTable.js if:

  • ✅ You want simple, clean API
  • ✅ You need small bundle size
  • ✅ You want 80% features in 10% size

Use TanStack Table if:

  • ✅ You need advanced features (grouping, pivoting, etc.)
  • ✅ You're building complex data grids
  • ✅ Bundle size is not a concern

🗺️ Roadmap

v0.1.0 (Current)

  • ✅ Core library
  • ✅ React adapter
  • ✅ Vue adapter
  • ✅ Pagination, sorting, filtering
  • ✅ TypeScript support

v0.2.0 (Planned)

  • ⬜ Vanilla JS adapter
  • ⬜ Column resizing module
  • ⬜ Export module (CSV, JSON)
  • ⬜ Server-side operations

v0.3.0 (Future)

  • ⬜ Virtual scrolling module
  • ⬜ Row selection module
  • ⬜ Svelte adapter
  • ⬜ Angular adapter

📞 Support


Made with ❤️ for modern web development

About

The **DataTables alternative** you've been waiting for - Super lightweight, framework-agnostic table library

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors