A few years ago, if you asked “what React table should I use?”, the conversation was mostly about rendering rows, sorting, maybe filtering, and how customizable the grid was.
In 2026, that’s not really the hard part anymore.
The hard part is building a datatable like Linear: something that already feels like part of a serious product.
I mean the stuff around the grid itself:
- filters
- saved views
- URL state
- bulk actions
- grouping
- persistence
- server-side loading
- shareable state
- keyboard-friendly workflows
- a UI that feels coherent instead of stitched together
I know this because I ended up building the same thing 4 times across different React projects.
And every time, the pattern was the same.
The grid itself was only a small part of the work.
The real engineering time disappeared into all the surrounding UX and behavior that users start expecting once the table becomes part of a real workflow.
So eventually I stopped rebuilding it from scratch and turned it into a product: react-datatable.
What most React table libraries give you
Most table libraries sit at one of two ends:
1. Headless flexibility
This is great when you want total control.
But it also means you are still responsible for assembling the full table experience yourself:
- toolbar behavior
- filter UX
- saved views
- URL sync
- selection state
- bulk action flows
- persistence
- online query contracts
- empty/loading/error states
- all the UI glue between those pieces
2. Fully built grid products
These can be powerful, but often come with tradeoffs:
- the code does not really become yours
- customization can feel constrained
- the UX can feel like “a grid inside your app” instead of “part of your product”
- agent-driven changes are harder when the core behavior lives outside your codebase
That middle ground is what I wanted.
What I actually wanted: a datatable like Linear
When I say “a datatable like Linear”, I do not mean copying Linear’s exact UI.
I mean the product shape.
A table that already behaves like something users can live in.
That usually means:
- fast search
- useful filters
- views worth saving
- URL-backed state
- bulk actions
- consistent keyboard behavior
- support for larger datasets
- a UX that feels deliberate rather than improvised
That’s the gap I built react-datatable for.
The core idea behind react-datatable
react-datatable is a source-owned React datatable.
That part matters.
Instead of giving you a black-box component you configure from the outside, it gives you code you can actually own, copy into your app, and adapt like part of your own product.
That makes it feel much closer to the appeal of shadcn:
- local source
- easy to inspect
- easy to modify
- easy to extend
- no weird boundary between “their component” and “your app”
So the goal is not just “yet another React grid”.
The goal is:
a production-shaped React datatable with source ownership.
Why source ownership matters more in 2026
This matters even more now because a lot of frontend work is increasingly done with coding agents.
Agents are great when they can work inside a codebase with clear seams and local ownership.
They are much less useful when the most important product behavior is trapped behind an external abstraction you can only poke through props.
With source-owned components, agents can:
- modify table UI directly
- add app-specific columns and actions
- change saved-view behavior
- extend row previews
- adapt bulk actions to backend workflows
- refactor state flows without fighting a black box
That’s a very different developer experience.
And honestly, I think this becomes a serious advantage in 2026.
A basic local example
Here is a stripped-down local-mode example:
import { Datatable, type DatatableColumn } from "./react-datatable"
type Customer = {
id: string
company: string
status: string
seats: number
}
const columns: DatatableColumn<Customer>[] = [
{
id: "company",
accessorKey: "company",
header: "Company",
filterType: "text",
},
{
id: "status",
accessorKey: "status",
header: "Status",
filterType: "select",
},
{
id: "seats",
accessorKey: "seats",
header: "Seats",
filterType: "number",
},
]
export function CustomersTable({ rows }: { rows: Customer[] }) {
return (
<Datatable
columns={columns}
data={rows}
getRowId={(row) => row.id}
toolbar={{
quickSearch: true,
filterButton: true,
displayOptions: true,
}}
selection={{ enabled: true }}
virtualization={{ mode: "viewport", estimateRowHeight: 44, overscan: 8 }}
/>
)
}
That already gets you much closer to a real product table than just “render some rows”.
A more realistic example
This is where the shape starts to matter more.
import { Datatable, type DatatableColumn, type DataTableBulkAction } from "./react-datatable"
type Customer = {
id: string
name: string
company: string
status: "Active" | "Trial" | "Paused"
plan: "Starter" | "Team" | "Enterprise"
seats: number
revenue: number
}
const columns: DatatableColumn<Customer>[] = [
{
id: "name",
header: "Name",
accessorKey: "name",
enableSorting: true,
enableFiltering: true,
filterType: "text",
},
{
id: "status",
header: "Status",
accessorKey: "status",
enableSorting: true,
enableFiltering: true,
enableGrouping: true,
filterType: "text-list",
filterOptions: {
options: [
{ label: "Active", value: "Active" },
{ label: "Trial", value: "Trial" },
{ label: "Paused", value: "Paused" },
],
},
},
{
id: "revenue",
header: "Revenue",
accessorKey: "revenue",
enableSorting: true,
enableFiltering: true,
filterType: "number",
cell: ({ getValue }) => `$${Number(getValue()).toLocaleString()}`,
},
]
const bulkActions: DataTableBulkAction<Customer>[] = [
{
id: "export",
title: "Export selected customers",
keywords: ["csv", "download"],
onSelect: (context) => {
console.log(`Export ${context.selectedCount} customers`)
context.clearSelection()
context.closeDialog()
},
},
]
export function RevenueTable({ rows }: { rows: Customer[] }) {
return (
<Datatable
data={rows}
columns={columns}
getRowId={(row) => row.id}
toolbar={{
quickSearch: { placeholder: "Search customers..." },
filterButton: true,
displayOptions: true,
copyLink: false,
views: false,
}}
initialState={{
sorting: [{ id: "name", desc: false }],
}}
stickyColumnsCount={1}
selection={{
enabled: true,
mode: "multi",
allowSelectAllMatching: true,
}}
bulkActions={{
triggerLabel: "Actions",
actions: bulkActions,
}}
virtualization={{
mode: "viewport",
rowOverscanCount: 10,
columnOverscanCount: 2,
}}
/>
)
}
This is the kind of surface I mean.
Not just “a table”.
A workflow surface.
Online mode matters too
The other place teams lose a lot of time is when the table outgrows local-only assumptions.
What starts as a simple client-side table often needs to become:
server-filtered
server-sorted
paginated
groupable
shareable
stable under larger datasets
That transition is where a lot of earlier choices break down.
Here’s what online mode looks like:
import { Datatable } from "./react-datatable"
<Datatable
columns={columns}
getRowId={(row) => row.id}
online={{
mode: "pagination",
queryKey: ["customers"],
pageSize: 50,
supportedGroupingColumns: ["status"],
query: (input) =>
fetch("/api/customers/table", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input),
}).then((response) => response.json()),
}}
/>
That matters because the product should not need a full rewrite just because the dataset got real.
Why I think this is the best React datatable framework for 2026
Obviously I’m biased — I built it.
But I also built this kind of thing repeatedly before I productized it, and that’s exactly why I think the framing is different.
I think the best React datatable framework for 2026 should do all of these well:
Feel production-ready
- not just rows and columns
- but filters, views, persistence, bulk actions, and state flows
Be source-owned
- closer to shadcn than to a locked box
- easy to adapt inside a real app
Scale from local to server-backed
- without forcing a redesign
Work well with coding agents
- local code
- clear seams
- understandable contracts
- modifiable UI
Save real developer time
- not 20 minutes in setup
- but weeks or months of UX integration work
That’s the bar I was trying to hit with react-datatable.
If your goal is “datatable like Linear”, this is the actual checklistIf that phrase brought you here, I’d use this checklist:
- Can I own the source?
- Can I change the UI deeply?
- Can I support saved views and URL state?
- Can I handle bulk actions cleanly?
- Can I move from local mode to online mode?
- Can I work on it effectively with coding agents?
- Does it feel like part of my product instead of a bolted-on grid?
That’s a much better decision framework than just comparing feature matrices.
Final thought
After building the same React datatable shape 4 times, I stopped believing the hard part was “finding a grid”.
The hard part is building the surrounding product behavior without losing months to glue code and edge cases.
That’s why I built react-datatable.
If you’re trying to build a datatable like Linear in React — with source ownership, strong UX, and code that agents can actually help you extend — that’s exactly what it’s for.
Top comments (0)