The DataTables alternative you've been waiting for - Super lightweight, framework-agnostic table library under 26KB
| 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 | ✅ Multi-framework | ✅ Multi-framework | |
| Headless | ✅ Yes | ❌ No | ✅ Yes | ❌ No |
| Learning Curve | ✅ Easy | ❌ Steep | ||
| Performance (10k rows) | ✅ Excellent | ✅ Excellent | ✅ Excellent |
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-reactPackages:
@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
- ✅ 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
- 🚀 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
- 🧹 Clean API - Intuitive, consistent methods
- 📘 Full TypeScript - IntelliSense everywhere
- 🎨 Headless - Complete styling freedom
- 🔧 Framework Adapters - Native hooks/composables
- 📚 Well Documented - Clear examples & API docs
npm install @herolabid/litetable-core @herolabid/litetable-reactimport { 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>
)
}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>npm install @herolabid/litetable-core @litetable/vanillaimport { 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)
})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 */}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
})Use cell function for custom rendering:
{
id: 'status',
header: 'Status',
cell: (value, row) => (
<span className={`badge badge-${value}`}>
{value}
</span>
)
}Subscribe to table updates:
table.tableInstance.on('sort', (state) => {
console.log('Sorted:', state.sortState)
})
table.tableInstance.on('search', (state) => {
console.log('Searched:', state.searchTerm)
})LiteTable.js is unstyled by default. Choose your approach:
.my-table {
border-collapse: collapse;
width: 100%;
}
.my-table th {
background: #f3f4f6;
padding: 12px;
text-align: left;
}<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><table className="table table-striped table-hover">
<thead>...</thead>
</table>| 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- Use debounced search for search inputs:
import { useDebouncedSearch } from '@herolabid/litetable-react'
const [searchValue, setSearch] = useDebouncedSearch(table.search, 300)- Pagination for large datasets:
pagination: {
page: 1,
pageSize: 25 // Render only 25 rows
}- Virtual scrolling (future module) for 100k+ rows
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
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# 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 devMIT © Irfan Arsyad
Inspired by:
- TanStack Table - Headless architecture
- List.js - Minimalist approach
- DataTables - Feature completeness
| LiteTable.js | DataTables | |
|---|---|---|
| Size | 8-15KB | ~180KB (with jQuery) |
| TypeScript | ✅ Native | ❌ |
| Modern frameworks | ✅ First-class | |
| jQuery dependency | ✅ Zero | ❌ Required |
| Headless | ✅ Yes | ❌ No |
| LiteTable.js | TanStack Table | |
|---|---|---|
| Size | ~11KB | ~15KB |
| Learning curve | ✅ Easy | |
| API simplicity | ✅ Simple | |
| Features | ✅ 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
- ✅ Core library
- ✅ React adapter
- ✅ Vue adapter
- ✅ Pagination, sorting, filtering
- ✅ TypeScript support
- ⬜ Vanilla JS adapter
- ⬜ Column resizing module
- ⬜ Export module (CSV, JSON)
- ⬜ Server-side operations
- ⬜ Virtual scrolling module
- ⬜ Row selection module
- ⬜ Svelte adapter
- ⬜ Angular adapter
Made with ❤️ for modern web development
