A flexible, fully-typed data table for React, Vue 3, and vanilla JS — with sorting, filtering, column visibility, and row grouping built in.
React demo · Vue demo · Vanilla demo
| Package | Description |
|---|---|
@vates/flexi-table-react |
React component and hook |
@vates/flexi-table-vue |
Vue 3 component and composable |
@vates/flexi-table-vanilla |
Vanilla JS, no framework required |
@vates/flexi-table-core |
Framework-agnostic logic (pure TS) |
- Multi-column sort
- Value checklist filters and numeric range filters
- Column visibility toggle
- Row grouping (grouped column hides from the table automatically)
- Row selection with checkboxes — select all (across pages), group selection, indeterminate state
- Client-side pagination
- i18n via a
labelsprop — defaults to English, with built-in locales for FR, ES, DE, PT - Custom cell rendering via render props (React), scoped slots (Vue), or
formatstring functions (vanilla) - Fully typed with TypeScript generics (
TRow extends object)
npm install @vates/flexi-table-reactimport { DataTable, type ColumnDef } from '@vates/flexi-table-react'
interface User {
id: number
name: string
role: string
salary: number
}
const COLUMNS: ColumnDef<User>[] = [
{ key: 'name', label: 'Name', type: 'string' },
{ key: 'role', label: 'Role', type: 'string', groupable: true },
{
key: 'salary',
label: 'Salary',
type: 'number',
format: (v) => Number(v).toLocaleString() + ' €',
},
]
export default function App() {
return <DataTable data={users} columns={COLUMNS} rowKey="id" />
}Custom cell rendering with render props:
{ key: 'role', label: 'Role', type: 'string',
render: (value, row) => <Badge label={String(value)} />,
renderFilterLabel: value => <Badge label={value} /> }npm install @vates/flexi-table-vue<script setup lang="ts">
import { DataTable, type ColumnDef } from '@vates/flexi-table-vue'
interface User {
id: number
name: string
role: string
salary: number
}
const COLUMNS: ColumnDef<User>[] = [
{ key: 'name', label: 'Name', type: 'string' },
{ key: 'role', label: 'Role', type: 'string', groupable: true },
{
key: 'salary',
label: 'Salary',
type: 'number',
format: (v) => Number(v).toLocaleString() + ' €',
},
]
</script>
<template>
<DataTable :data="users" :columns="COLUMNS" row-key="id">
<template #cell-role="{ value }">
<Badge :label="String(value)" />
</template>
<template #filter-role="{ value }">
<Badge :label="value" />
</template>
<template #group-role="{ value }">
<Badge :label="String(value)" />
</template>
</DataTable>
</template>npm install @vates/flexi-table-vanillaimport { createFlexiTable, type ColumnDef } from '@vates/flexi-table-vanilla'
const COLUMNS: ColumnDef<User>[] = [
{ key: 'name', label: 'Name', type: 'string' },
{ key: 'role', label: 'Role', type: 'string', groupable: true },
{
key: 'salary',
label: 'Salary',
type: 'number',
format: (v) => Number(v).toLocaleString() + ' €',
},
]
const table = createFlexiTable(document.getElementById('table')!, {
data: users,
columns: COLUMNS,
rowKey: 'id',
})
// Update later
table.setData(newUsers)
table.destroy()CSS is injected automatically into <head>. Cell output is string-only — use format to control rendering.
All UI strings are in English by default. Use a built-in locale or supply any overrides via the labels prop:
import { LABELS_FR } from '@vates/flexi-table-react' // or -vue or -vanilla
<DataTable labels={LABELS_FR} ... />Built-in locales: LABELS_EN (default), LABELS_FR, LABELS_ES, LABELS_DE, LABELS_PT.
You can also pass a Partial<DataTableLabels> to override individual strings — it is shallow-merged over the default English labels.
interface ColumnDefBase<TRow extends object> {
key: keyof TRow & string // must be a key of TRow
label: string
type?: 'string' | 'number' | 'date' // controls filter UI; default: 'string'
width?: number
format?: (value: unknown) => string // plain-string formatter (both adapters)
sortable?: boolean // default: true
filterable?: boolean // default: true
groupable?: boolean // default: false
}React extends this with render? and renderFilterLabel?. Vue uses scoped slots instead.
See CONTRIBUTING.md.
MIT