Skip to content

Introduction

Open-code React data tables for shadcn/ui—composable DataTable* components, TanStack Table state, and copy-paste registry installs.

Nobody’s table, everyone’s solution.

Just like Shadcn, Niko Table is not a component library. Instead, it’s a comprehensive DataTable component that you copy into your project and customize to your needs. It’s built with TanStack Table and Shadcn UI, providing enterprise-grade features while remaining fully under your control.

Built for real-world applications with features like:

  • Sorting (single and multi-column)
  • Filtering (global search and column filters)
  • Pagination (client and server-side)
  • Row selection and bulk actions
  • Column visibility and reordering
  • Virtual scrolling for large datasets
  • Export to CSV

Start simple and add features as you need them:

  1. Simple Table - Just render data (< 5 minutes)
  2. Basic Table - Add pagination and sorting (+ 5 minutes)
  3. Search Table - Add global search (+ 5 minutes)
  4. Filter Table - Add column filters (+ 10 minutes)
  5. Advanced Table - Add virtualization, sidebars, etc. (+ 15 minutes)

Since you own the code, you can:

  • Modify any component
  • Add custom features
  • Change styling
  • Integrate with your backend
  • No version lock-in

Built on your shadcn generation’s primitives (Radix UI or Base UI) with semantic table markup where possible:

  • Keyboard support in sort/filter menus and toolbar controls
  • ARIA labels on filter triggers, sliders, and clear actions
  • Screen-reader-friendly patterns via shadcn/ui components
  • jsx-a11y lint rules on docs and source

We do not claim third-party WCAG certification; treat complex tables (virtualization, DnD, pinning) like any custom UI and verify with your own accessibility checklist.

  • DataTable uses a full-width overflow-auto scroll region for wide column sets on small screens
  • Popovers and filter panels respect available viewport width
  • Optional DataTableAside for a collapsible detail panel (see Aside Table)
  • Toolbars are plain flex layouts — wrap or hide filters on mobile in your app as needed

The DataTable uses a two-layer architecture for maximum flexibility:

Components (data-table-*.tsx in /components folder) - Context-aware wrapper components that use useDataTable() hook to automatically get the table from DataTableRoot context. These eliminate prop drilling and are the recommended way to use components:

  • DataTableSearchFilter, DataTableFilterMenu, DataTableSortMenu, DataTablePagination, etc.

Filters (table-*.tsx in /filters folder) - Core implementation components that accept a table prop directly and use TanStack Table hooks (like table.getState(), table.setGlobalFilter(), etc.). These can be used standalone:

  • TableSearchFilter, TableFilterMenu, TableSortMenu, etc.

Why this architecture?

  • Use DataTable* components from their direct paths (e.g. @/components/niko-table/components/data-table-pagination) when you want context-based, zero-config usage
  • Use Table* components from filters when you want to build custom components or manage the table instance yourself
  • All filter components use TanStack Table hooks directly, giving you full control
// Recommended: Use context-based Action components
<DataTableRoot data={data} columns={columns}>
<DataTableSearchFilter /> {/* Automatically gets table from context */}
<DataTable>
<DataTableHeader />
<DataTableBody />
</DataTable>
<DataTablePagination />
</DataTableRoot>
// Advanced: Use Filter components directly
const table = useReactTable({ data, columns, ... })
<TableSearchFilter table={table} /> {/* Pass table prop directly */}

Build tables by composing components - start simple and add features as needed:

<DataTableRoot data={data} columns={columns}>
<DataTableToolbarSection>
<DataTableSearchFilter />
<DataTableFilterMenu />
</DataTableToolbarSection>
<DataTable>
<DataTableHeader />
<DataTableBody />
</DataTable>
<DataTablePagination />
</DataTableRoot>

Niko Table is mix-and-match: install only the registry items you need, render only the children you want, and swap body strategies without rewriting column defs.

Layer What you choose Notes
Root DataTableRoot Required. Optional controlled state, config overrides, getRowId for selection/DnD/expansion
Toolbar DataTableToolbarSection + any of search, faceted, filter menu, view menu, clear Omitted entirely for minimal tables
Table shell DataTable with height / max-h-* when virtualizing Virtualizer needs a bounded scroll container
Header / body Regular: DataTableHeader + DataTableBody Default path
Virtualized: DataTableVirtualizedHeader + DataTableVirtualizedBody 10k+ rows
Row DnD: DataTableRowDndProvider (outside table) + DataTableDndBody Do not combine with sort/filter
Column DnD: DataTableColumnDndProvider + draggable headers/cells Safe with other features
Loading / empty DataTableSkeleton, DataTableEmptyBody or composable empty pieces Siblings inside the body
Footer DataTablePagination, DataTableSelectionBar Optional
Row actions One RowMenu* component + useDataTableRow in kebab and DataTableRowContextMenuSlot Row context menu
Escape hatch Table* filters with your own table instance Custom layouts without context

DataTableRoot runs feature detection on children (detectFeaturesFromChildren) so pagination, filtering, and sorting turn on when you add the matching components — you rarely hand-roll a giant config object.

This DataTable provides you with:

  • TanStack Table integration - Built on the powerful headless table library
  • Composable components - Build complex UIs from simple, reusable pieces
  • State management - Context-based state sharing with hook-based flexibility
  • Performance optimization - Virtual scrolling, memoization, and efficient rendering
  • Accessibility - shadcn/ui primitives (Radix or Base UI), keyboard-friendly filters/menus, jsx-a11y linting (verify end-to-end in your app)
  • TypeScript - Fully typed with comprehensive type definitions

This project follows the Shadcn philosophy:

You copy the DataTable component code into your project (not install it as a package). However, you still need to install the required dependencies:

Required Dependencies:

  • @tanstack/react-table - Core table library
  • Shadcn UI components (via npx shadcn@latest add ...) - UI primitives
  • Optional: @tanstack/react-virtual, nuqs, @dnd-kit/* for advanced features

What You Copy:

  • All DataTable component files from /components/niko-table/
  • Full source code that you can read, modify, and customize

Benefits:

  • ✅ No black box - See exactly how everything works
  • ✅ Full control - Modify any component to fit your needs
  • ✅ Easy to customize - Change styling, behavior, or add features
  • ✅ No version lock-in - You control when to update
  • ✅ Learn by reading - Understand the implementation

Build complex tables by composing simple components:

// Start simple
<DataTableRoot data={data} columns={columns}>
<DataTable>
<DataTableHeader />
<DataTableBody />
</DataTable>
</DataTableRoot>
// Add features incrementally
<DataTableRoot data={data} columns={columns} config={{ enablePagination: true }}>
<DataTableToolbarSection>
<DataTableSearchFilter />
</DataTableToolbarSection>
<DataTable>
<DataTableHeader />
<DataTableBody />
</DataTable>
<DataTablePagination />
</DataTableRoot>
// Go advanced
<DataTableRoot
data={data}
columns={columns}
config={{
enablePagination: true,
enableFilters: true,
enableRowSelection: true,
}}
>
<DataTableToolbarSection className="justify-between">
<div className="flex gap-2">
<DataTableSearchFilter />
<DataTableFilterMenu />
</div>
<div className="flex gap-2">
<DataTableViewMenu />
<DataTableSortMenu />
</div>
</DataTableToolbarSection>
<DataTable>
<DataTableHeader />
<DataTableBody>
<DataTableSkeleton />
<DataTableEmptyBody />
</DataTableBody>
</DataTable>
<DataTablePagination />
</DataTableRoot>

Full TypeScript support throughout:

type User = {
id: string
name: string
email: string
}
const columns: DataTableColumnDef<User>[] = [
{
accessorKey: "name", // ✅ Type-safe
header: "Name",
cell: ({ row }) => row.original.email, // ✅ Autocomplete
},
]
Feature This DataTable Component Libraries
Customization ✅ Full control ❌ Limited
Bundle size ✅ Copy what you need ❌ Entire library
Learning curve ✅ See the source ❌ Read docs
Dependencies ✅ Standard deps only ❌ Library-specific
Updates ✅ Copy new features ❌ Breaking changes
Feature This DataTable From Scratch
Time to implement ✅ Minutes ❌ Days/weeks
Accessibility ✅ Baseline included ❌ Must implement
Mobile support ✅ Ready ❌ Must build
Advanced features ✅ Available ❌ Complex to build
Best practices ✅ Included ❌ Must learn

Ready to get started?

  1. Installation - Set up your project
  2. Simple Table - Your first table
  3. Basic Table - Add common features
  4. Search Table - Add search
  5. Faceted Filter Table - Advanced filtering
  6. Advanced Table - Master level

Questions? Ideas? Contributions?

Built on top of:

  • TanStack Table by Tanner Linsley - The headless table library that powers everything
  • Shadcn UI by Shadcn - Beautiful, accessible component primitives
  • sadmann7’s work - Major inspiration for filter components and table patterns:
    • TableCN - Inspired our filter menu, inline filter, faceted filter, and slider filter implementations
    • DiceUI Sortable - Drag and drop sortable for row reordering
  • nuqs by François Best - Type-safe search params state manager for URL state management
  • Web Dev Simplified Registry by Kyle Cook - Registry implementation pattern

MIT License - use it freely in your projects!