Data-table primitives built for Svelte 5.
Inu Tables is currently focused on low-level reactive building blocks: column entities, row/cell wrappers, filters, and shared types.
pnpm add inu-tables
# or
npm install inu-tables
Svelte 5 is a peer dependency.
inu-tables currently exports the following symbols from the package root:
import {
TableModel,
PaginationState,
SortingState,
GlobalSearchState,
RowSelectionState,
ColumnVisibilityState,
ColumnFilterState,
ColumnState,
RowState,
CellState,
ColumnFilter,
TextColumnFilter,
NumberColumnFilter,
DateColumnFilter
} from 'inu-tables';
import type {
ResolvedCell,
RowFilter,
SortDirection,
FilterFn,
SortFn,
SearchFn,
NumberRange,
DateRange,
ColumnDef,
ColumnDefWithKey,
ColumnDefWithFn,
TableOptions
} from 'inu-tables';
TableState, ServerTableState, ServerTableParams, and ServerTableResult are not part of the current published API.
Reactive table engine used by the examples in this repository.
Constructor:
new TableModel<TRow>({
data,
columns,
rowKey,
state?,
options?
});
Common members:
columnsrowFilterssortingglobalSearchcolumnVisibilitypaginationrowSelectionfilteredRowsvisibleRowsrowCountpageCountselectedRowsallSelectedsomeSelectedgetCells(row)getKey(row)PaginationStateSortingState<TRow>GlobalSearchState<TRow>RowSelectionState<TRow>ColumnVisibilityState<TRow>ColumnFilterState<TFilterValue>Represents a single column definition plus reactive column state.
Constructor:
new ColumnState<TRow>(def: ColumnDef<TRow>);
Key members:
id: stringheader: stringaccessor: (row: TRow) => unknownsortable: booleansortFn: SortFn<TRow> | undefinedfilterable: booleanfilter: ColumnFilter<any>cellFn: ((value: unknown, row: TRow) => string) | undefinedsearchable: booleansearchFn: SearchFn<TRow> | undefinedshow ($state<boolean>, default true)isFiltered ($derived<boolean>)Example:
type Person = { id: number; firstName: string; age: number };
const nameCol = new ColumnState<Person>({
accessorKey: 'firstName',
header: 'First name',
sortable: true,
filterable: true
});
nameCol.filter.value = 'ali';
Lightweight wrapper for a raw row object.
Constructor:
new RowState<TRow>(data: TRow, id: TRow[keyof TRow]);
Members:
data: TRowid: TRow[keyof TRow]Represents one row/column intersection.
Constructor:
new CellState<TRow>(row: RowState<TRow>, column: ColumnState<TRow>);
Members:
row: RowState<TRow>column: ColumnState<TRow>value: unknowndisplayValue: stringGeneric reactive filter wrapper.
Constructor:
new ColumnFilter<TFilterValue>({
fn,
reset?,
initialValue?
});
Members:
value ($state<TFilterValue | undefined>)active ($derived<boolean>)fn: FilterFnreset: () => voidCase-insensitive contains match.
value type: string | undefinedvalue is non-emptyInclusive numeric range match.
value type: { min?: number; max?: number }min or max is set to a finite numberInclusive day-level date range match (UTC normalization).
value type: { min?: Date | string; max?: Date | string }min or max resolves to a valid dateExample:
const numeric = new NumberColumnFilter();
numeric.value = { min: 10, max: 25 };
const dates = new DateColumnFilter();
dates.value = { min: '2026-01-01', max: '2026-12-31' };
Union of:
ColumnDefWithKey<TRow>: { accessorKey, header, ... }ColumnDefWithFn<TRow>: { id, accessorFn, header, ... }Common options:
header: stringsortable?: booleansortFn?: SortFn<TRow>filterable?: booleanfilterType?: 'text' | 'number' | 'date'filterFn?: FilterFncell?: (value: unknown, row: TRow) => stringsearchable?: booleansearchFn?: SearchFn<TRow>ResolvedCell<TRow>: { column, value, displayValue }RowFilter<TRow>: (row: TRow) => booleanSortDirection: 'ascending' | 'descending'FilterFn: (cellValue: unknown, filterValue: unknown) => booleanSortFn<TRow>: (a: TRow, b: TRow) => numberSearchFn<TRow>: (value, displayValue, row, query) => booleanNumberRange: { min?: number; max?: number }DateRange: { min?: Date | string; max?: Date | string }TableOptions<TRow>: currently exported for compatibilityThe examples in src/routes/examples now import TableModel and state classes from the package root just like consumers can.
MIT