@nccirtu/tablefy
v0.9.2
Published
A schema-driven toolkit for React tables and forms, built with TanStack Table and shadcn/ui. Designed for Laravel + Inertia.js v2 + Wayfinder.
Maintainers
Readme
Tablefy
A powerful, type-safe React toolkit for building schema-driven Data Tables and Forms. Built on shadcn/ui and designed for Laravel + Inertia.js v2 + Wayfinder.
Features
Data Tables
- Beautiful UI - Built on shadcn/ui components with Tailwind CSS
- Search & Filter - Built-in search and advanced filtering
- Sorting & Pagination - Full sorting and pagination support (client & server-side)
- 14+ Column Types - Text, Badge, Date, Link, Progress, Avatar, Icon, Image, Actions, and more
- Confirm Dialogs - Built-in confirmation system for destructive actions
Forms
- Schema-Driven - Define forms with a fluent builder API
- 11 Field Types - TextInput, Textarea, Select, Checkbox, CheckboxGroup, Toggle, RadioGroup, DatePicker, FileUpload, Repeater, Hidden
- Layout Builders - Sections (collapsible cards), Tabs, Wizard (multi-step)
- Field Dependencies - Show/hide/enable/disable fields based on other field values
- Grid Layout - Responsive multi-column grids with columnSpan support
Inertia.js Integration
- useInertiaForm - Bridge FormSchema with Inertia's
useFormfor seamless state management - useServerTable - Server-side pagination, sorting, and filtering with
router.visit() - Precognition - Live server-side validation on field blur
- Wayfinder - Type-safe route helpers as form action URLs
Core
- Type-Safe - Complete TypeScript support with generics and type inference
- Fluent API - Chainable builder pattern for easy, readable configuration
- Tree-Shakeable - Sub-path exports (
/forms,/inertia,/columns) for optimal bundle size - Zero Breaking Changes - Forms and Inertia are purely additive to the existing table API
Installation
npm install @nccirtu/tablefyQuick setup with CLI:
npx tablefy initPeer Dependencies
# Core (required)
npm install @tanstack/react-table lucide-react class-variance-authority clsx tailwind-merge
# shadcn/ui components (install what you need)
npx shadcn@latest add button table checkbox dropdown-menu input select badge progress tooltip label card tabs textarea switch radio-group calendar popover separator
# Optional: Inertia.js integration
npm install @inertiajs/react
# Optional: Zod validation
npm install zodConfigure Tailwind
Tailwind v4 (Laravel 12):
@import "tailwindcss";
@source '../../node_modules/@nccirtu/tablefy/dist';Tailwind v3:
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@nccirtu/tablefy/dist/**/*.{js,mjs}",
],
};See the full installation guide for framework-specific instructions.
Quick Start: Data Table
import { DataTable, TableSchema, TextColumn, BadgeColumn, DateColumn } from "@nccirtu/tablefy";
type User = {
id: string;
name: string;
email: string;
status: "active" | "inactive";
createdAt: Date;
};
const columns = TableSchema.make<User>()
.columns(
TextColumn.make("name").label("Name").sortable(),
TextColumn.make("email").label("Email").limit(30),
BadgeColumn.make("status").label("Status").variants({
active: "success",
inactive: "secondary",
}),
DateColumn.make("createdAt").label("Created").relative(),
)
.build();
function UsersTable({ users }: { users: User[] }) {
return (
<DataTable
columns={columns}
data={users}
config={{
search: { enabled: true },
pagination: { enabled: true },
}}
/>
);
}Quick Start: Form
import { FormSchema, TextInput, Select, Textarea, FormRenderer } from "@nccirtu/tablefy/forms";
import { useState } from "react";
type CreateUser = {
name: string;
email: string;
role: string;
bio: string;
};
const schema = FormSchema.make<CreateUser>()
.title("Create User")
.description("Add a new team member")
.columns(2)
.bordered()
.fields(
TextInput.make<CreateUser>("name").label("Name").required(),
TextInput.make<CreateUser>("email").label("Email").email().required(),
Select.make<CreateUser>("role")
.label("Role")
.options([
{ value: "admin", label: "Admin" },
{ value: "editor", label: "Editor" },
{ value: "viewer", label: "Viewer" },
])
.required(),
Textarea.make<CreateUser>("bio").label("Biography").rows(4).columnSpan(2),
)
.actions((a) => a.submit({ label: "Create User" }).cancel({ label: "Cancel" }))
.build();
function CreateUserPage() {
const [data, setData] = useState<CreateUser>({ name: "", email: "", role: "", bio: "" });
const [errors, setErrors] = useState({});
return (
<FormRenderer
schema={schema}
data={data}
errors={errors}
onChange={(field, value) => setData((prev) => ({ ...prev, [field]: value }))}
onSubmit={() => console.log("Submit:", data)}
/>
);
}Quick Start: Inertia.js + Laravel
import { FormSchema, TextInput, Select, FormRenderer } from "@nccirtu/tablefy/forms";
import { useInertiaForm } from "@nccirtu/tablefy/inertia";
type CreateUser = { name: string; email: string; role: string };
const schema = FormSchema.make<CreateUser>()
.title("Create User")
.columns(2)
.fields(
TextInput.make<CreateUser>("name").label("Name").required(),
TextInput.make<CreateUser>("email").label("Email").email().required(),
Select.make<CreateUser>("role")
.label("Role")
.options([
{ value: "admin", label: "Admin" },
{ value: "editor", label: "Editor" },
])
.columnSpan(2),
)
.actions((a) => a.submit({ label: "Create" }).cancel({ label: "Cancel", href: "/users" }))
.build();
export default function CreateUserPage() {
const { data, errors, onChange, onSubmit, processing } = useInertiaForm<CreateUser>({
schema,
url: "/users",
method: "post",
});
return (
<FormRenderer
schema={schema}
data={data}
errors={errors}
onChange={onChange}
onSubmit={onSubmit}
processing={processing}
/>
);
}Column Types
| Column Type | Description | Key Methods |
|---|---|---|
| TextColumn | Simple text display | sortable(), prefix(), suffix(), limit(), uppercase() |
| NumberColumn | Numbers & currency | money(), percent(), decimals(), locale() |
| DateColumn | Dates & times | short(), long(), relative(), datetime(), withIcon() |
| BadgeColumn | Status badges | variants(), boolean(), status() |
| LinkColumn | Clickable links | href(), external(), underline(), openInNewTab() |
| ProgressColumn | Progress bars | max(), colorByThreshold(), showPercentage(), format() |
| AvatarGroupColumn | Avatar groups | maxVisible(), size(), overlap(), fields(), showNames() |
| IconColumn | Status icons | boolean(), priority(), onlineStatus(), verification(), states() |
| ImageColumn | Single images | size(), rounded(), circular(), fallback() |
| CheckboxColumn | Selection checkboxes | -- |
| ActionsColumn | Dropdown menus | view(), edit(), delete(), action(), link() |
| EnumColumn | Enum display | options() |
Form Field Types
| Field Type | Description | Key Methods |
|---|---|---|
| TextInput | Single-line text | email(), password(), number(), url(), tel(), prefix(), suffix(), minLength(), maxLength() |
| Textarea | Multi-line text | rows(), minLength(), maxLength(), autoResize() |
| Select | Dropdown select | options(), multiple(), searchable(), clearable(), loadOptions() |
| Checkbox | Boolean checkbox | (inherits base methods) |
| CheckboxGroup | Multiple checkboxes | options(), columns() |
| Toggle | On/off switch | onLabel(), offLabel() |
| RadioGroup | Radio buttons | options(), horizontal(), vertical() |
| DatePicker | Date calendar | minDate(), maxDate(), format(), includeTime(), locale() |
| FileUpload | File drag & drop | accept(), maxSize(), multiple(), maxFiles(), image(), pdf() |
| Repeater | Dynamic list | fields(), minItems(), maxItems(), addLabel(), orderable() |
| Hidden | Hidden input | (inherits base methods) |
Layout Options
Sections (Collapsible Cards)
FormSchema.make<T>()
.fields(/* ... */)
.sections(
SectionBuilder.make("Personal").fields(["name", "email"]).columns(2),
SectionBuilder.make("Address").fields(["street", "city"]).collapsible(),
)
.build();Tabs
FormSchema.make<T>()
.fields(/* ... */)
.tabs(
TabBuilder.make("Profile").fields(["name", "email"]).icon(<User />),
TabBuilder.make("Settings").fields(["language", "timezone"]),
)
.build();Wizard (Multi-Step)
FormSchema.make<T>()
.fields(/* ... */)
.wizard(
WizardStep.make("Account").fields(["email", "password"])
.canProceed((d) => !!d.email && !!d.password),
WizardStep.make("Profile").fields(["name", "bio"]),
)
.build();Import Paths
// Everything
import { DataTable, TableSchema, TextColumn, FormSchema, TextInput } from "@nccirtu/tablefy";
// Columns only (tree-shakeable)
import { TextColumn, BadgeColumn } from "@nccirtu/tablefy/columns";
// Forms only (tree-shakeable, no TanStack Table)
import { FormSchema, TextInput, Select, FormRenderer } from "@nccirtu/tablefy/forms";
// Inertia integration (requires @inertiajs/react)
import { useInertiaForm, useServerTable } from "@nccirtu/tablefy/inertia";Documentation
- Installation Guide - Detailed setup instructions
- Data Tables Guide - Complete table API reference and examples
- Forms Guide - All form field types, layouts, and examples
- Inertia Integration - Server-side tables, useInertiaForm, Precognition
- Actions Column - Custom render functions and confirm dialogs
- Editable Columns - InputColumn and SelectColumn guide
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT Tablefy Contributors
Acknowledgments
Built with:
- TanStack Table - Headless table library
- shadcn/ui - Beautiful UI components
- Tailwind CSS - Utility-first CSS framework
- Inertia.js - The modern monolith
- Laravel - The PHP framework
