An open-source, zero-dependency table component built for ERP-style applications. Handles sorting, filtering, pagination, and rich column types out of the box — with full style customization and no runtime baggage.
- Zero runtime dependencies — only React as a peer dependency
- 7 built-in column types — text, number, date, boolean, badge, currency, link
- Quick filters — inline per-column filter pills in the header
- Sorting — single-column sorting with visual indicators
- Pagination — built-in page controls with configurable page size
- Custom renderers — override any column with a
renderfunction - Two data modes — controlled (
dataprop) or self-managed (requestprop for async fetching) - Full style control — CSS custom properties,
classNamesAPI, andstylesprop for every table slot - Framework-agnostic styling — ships plain CSS in
@layer flotable, works with Tailwind, CSS Modules, or vanilla CSS
npm install flotableFloTable requires React 18+ as a peer dependency.
import { FloTable } from 'flotable';
import 'flotable/dist/flotable.css';
const columns = [
{ key: 'name', header: 'Name', type: 'text' as const },
{ key: 'email', header: 'Email', type: 'text' as const },
{ key: 'role', header: 'Role', type: 'badge' as const, badgeColors: { Admin: '#e0f2fe', User: '#f0fdf4' } },
{ key: 'salary', header: 'Salary', type: 'currency' as const, currency: 'USD' },
];
const data = [
{ name: 'Alice', email: 'alice@example.com', role: 'Admin', salary: 95000 },
{ name: 'Bob', email: 'bob@example.com', role: 'User', salary: 72000 },
];
function App() {
return (
<FloTable
columns={columns}
data={data}
totalRows={data.length}
page={1}
onPageChange={(p) => console.log('Page:', p)}
/>
);
}<FloTable
columns={columns}
pageSize={20}
request={async ({ page, pageSize, sortState, quickFilters }) => {
const res = await fetch(`/api/users?page=${page}&size=${pageSize}`);
const json = await res.json();
return { data: json.rows, totalRows: json.total };
}}
/>| Type | Description | Extra Props |
|---|---|---|
text |
Plain text | — |
number |
Formatted number | locale |
date |
Formatted date string | locale |
boolean |
Checkmark / cross icon | — |
badge |
Colored pill for enum values | badgeColors |
currency |
Formatted money value | currency, locale |
link |
Clickable URL | — |
Any column can use a custom render function to override the default renderer.
FloTable ships plain CSS wrapped in @layer flotable. Every visual token uses a CSS custom property with a fallback, so you can theme the entire table without touching source files.
Override tokens on the root element or via the styles prop:
.my-table {
--flotable-border-color: #e5e7eb;
--flotable-header-bg: #f9fafb;
--flotable-row-hover-bg: #f3f4f6;
--flotable-font-size: 14px;
}Pass custom class names to any table slot:
<FloTable
classNames={{
root: 'my-table',
header: 'my-header',
row: 'my-row',
cell: 'my-cell',
pagination: 'my-pagination',
filterBar: 'my-filters',
}}
// ...
/>If your app uses Tailwind, declare the flotable layer before your Tailwind import so utility classes passed via classNames reliably override component defaults:
/* globals.css */
@layer flotable; /* lowest priority — component defaults */
@import "tailwindcss"; /* utilities layer beats flotable */| Prop | Type | Description |
|---|---|---|
columns |
ColumnDef<T>[] |
Column definitions (required) |
pageSize |
number |
Rows per page (default: 10) |
filterDefs |
FilterDef[] |
Explicit filter pill definitions |
autoFilters |
boolean |
Auto-generate filter pills from filterable columns |
showSearch |
boolean |
Show a global search input in the filter bar |
classNames |
FloTableClassNames |
Custom CSS classes for each table slot |
styles |
FloTableStyles |
Inline styles / CSS custom properties for each slot |
| Prop | Type | Description |
|---|---|---|
data |
T[] |
Current page rows |
totalRows |
number |
Total row count across all pages |
page |
number |
Active page (1-based) |
onPageChange |
(page: number) => void |
Page navigation callback |
sortState |
SortState<T> | null |
Current sort state |
onSortChange |
(sort: SortState<T> | null) => void |
Sort change callback |
quickFilters |
QuickFilterState |
Active filter values |
onFilterChange |
(filters: QuickFilterState) => void |
Filter change callback |
| Prop | Type | Description |
|---|---|---|
request |
FloTableRequestFn<T> |
Async function called on mount and on every state change |
packages/flotable/ # The published npm package
apps/demo/ # Next.js demo app (not published)
See CONTRIBUTING.md for setup instructions, code style rules, and the PR workflow.
MIT — Copyright (c) 2026 Fladeed