Turnkey Development of Interactive Tables with TanStack Table

Large tables start to slow down exactly when data becomes abundant: filters lag, sorting freezes, and users lose patience. We develop turnkey interactive tables with TanStack Table — from logic design to handing over a ready solution to your team. You get predictable performance with any volume of rows and a noticeable speedup of daily operations.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Frequently Asked Questions

Interactive tables on TanStack Table: where the logic breaks

A hand-rolled table breaks predictably: sorting, filters, pagination, and row selection live in different places — in component state, in refs, in handler closures.

Add virtualization or server-side loading, and these pieces start arguing with each other: the filter resets on re-render, the selection "migrates" to other rows after sorting, and the counter shows one thing while the screen shows another.

Each such defect takes a long time to track down, because the source of truth is smeared across a dozen places.

The second point of failure is render performance. While there are a hundred rows, everything is unnoticeable. On a sample of several thousand, the browser starts re-rendering the entire set on every keystroke in the search field, and the interface freezes for seconds.

This is cured not by "optimizing later," but by architecture: a table state model, row memoization, window virtualization, and separating client-side and server-side data processing.

TanStack Table is exactly about this: it doesn't draw the markup for you, but keeps the table state — sorting, filters, grouping, row selection, pagination — in one predictable place.

You get control over rendering and explicit points where server requests can be hooked in, without losing filters when data updates. Let's break down how this is handled in practice: from the data model to rolling back an unsuccessful release.

What a controlled table delivers: speed, stability, predictability

A controlled model is when the table's state (sorting, filters, pagination, row selection) lives in one place instead of being smeared across dozens of handlers inside the component.

We keep it in a controlled store and pass it into the table as input data — the interface stops "guessing" the current state and always renders exactly what's in the model.

The practical effect is visible on data volume: on selections of tens of thousands of rows, sorting by a column completes in fractions of a second, because recalculation runs over indexes rather than a full scan on every render.

Freezes when switching filters and scrolling disappear: heavy computations are moved out of the render loop, and rows appear as needed rather than all at once.

There is noticeably less code. The logic of selection, sorting, and pagination is described declaratively — one set of rules instead of a scattering of conditions, so the enhancement "add a column with a computed field" takes hours, not days.

A new engineer gets into the table by reading the model description rather than reading the entire component.

The load on the browser stops growing with the number of rows: memory stays at a stable level, and the interface is equally responsive on a hundred records and on a large selection.

We separately cover edge cases — empty result, loading error, slow server response: the user sees a clear state rather than a frozen screen.

Maintainability rests on predictability: filtering and sorting rules can be covered by checks separately from rendering, and the table's behavior is reproduced in tests without manually clicking through the interface.

Table operation modes: client-side, server-side, hybrid

The mode is determined not by the size of the table, but by where the data lives and who manages it. Client-side mode keeps the entire dataset in the browser's memory: sorting, filters, and pagination are computed locally, and the response to an action is instant.

The ceiling is the size of the dataset: up to several thousand rows is comfortable, beyond that memory and initial rendering start to noticeably lag.

Server-side pagination shifts slicing, sorting, and filtering to the backend: the browser receives only the current page.

This is how directories with hundreds of thousands of records work, but every action is a network request, and on a slow connection the interface "freezes" between clicks. Preloading neighboring pages and caching already-viewed slices mitigates this.

Hybrid mode takes the best of both: filters and sorting are handled by the server, while pagination and row virtualization are handled by the client.

A limited dataset is kept in memory, long lists are rendered as a window, and scrolling remains smooth even with tens of thousands of rows.

Mode When it fits Limitations
Client-side Up to several thousand rows, data changes rarely Memory growth, slower initial rendering
Server-side Large directories, frequent updates Latency on every request, requires a stable connection
Hybrid Thousands of rows with filters and sorting More complex synchronization of client and server state

We lock in the choice at the design stage: switching the mode later affects both the client-side logic and the API contracts.

Implementation stages: from auditing the current table to handover

Work on an interactive table starts not with code, but with analyzing what already exists: how the current table is structured, where it slows down on large datasets, which filtering and sorting scenarios people actually use, and which were left "just in case." Such a table audit shows what needs to be rewritten and what merely needs reconfiguring — and immediately sets the boundaries of the task.

Next, we design the state model: what lives in addressable parameters (filters, sorting, page), what lives locally, how data is loaded page by page and cached. This scheme determines whether the table will survive a page reload and whether the user will return to the same view.

  1. Table audit. We review the current code, measure behavior on real volumes, identify bottlenecks, and compile a list of what to keep unchanged.
  2. State model design. We determine which parameters are synchronized with the address, how row selection, grouping, and row expansion are structured, and where state is stored.
  3. Column configuration. We describe columns declaratively: widths, pinning, order, visibility, cell formatting, custom renderers for complex data types.
  4. Interaction assembly. We connect sorting, filters, search, pagination, and virtualization of long lists so that heavy datasets do not block the interface.
  5. Testing on data. We run the table on production exports: edge values, empty responses, slow queries, behavior on load failure.
  6. Documentation and code handover. We document the component structure, describe the column configuration and state model so that the client's team can add columns and rules without us.
  7. Post-launch support. We monitor behavior on real traffic, fine-tune performance, and address user feedback.

Each stage ends with a verifiable result, not a report of work done. Code handover includes not only the repository but also a clear scheme by which the table can be further developed.

Configuring columns, filters, and sorting for your scenario

Configuration starts with describing the columns: each one is assigned a data type, a display method, and calculation rules. Numeric columns get alignment and digit grouping, dates get a unified format and time zone, and text columns get truncation with expansion on click.

Calculated columns (for example, margin or variance from plan) are computed on the client side without a repeated request to the server, so recalculation during filtering happens instantly.

Filtering is built as composite: multiple conditions are combined with "and/or" logic, each tied to its own column and comparison type — range, inclusion in a list, substring.

The state of filters and sorting is stored in the address bar, so a link to a specific selection can be shared with a colleague or saved as a view.

Sorting supports multiple levels: first by department, then by date within it, then by amount; the user changes the order of levels by dragging.

  • Column types — text, number, date, status, calculated value; the cell editor and comparison rules depend on the type.
  • Composite filters — a set of conditions with "and/or" logic, saving sets as named views.
  • Multi-level sorting — up to several keys at once with a clear priority order.
  • Row grouping — collapsing by category with aggregates (sum, average, count) at the group level.
  • Column pinning — key columns stay on screen during horizontal scrolling of a wide table.
  • Conditional formatting — highlighting cells and rows by thresholds: overdue items, negative variances, exceeding the limit.
  • Editing and validation — editing cells directly in the table with value checks before sending to the server.

The visual part is configured separately from the logic: the user saves row density, column visibility, order, and width in their profile.

At the core is TanStack Table, a library with no imposed markup: we write the markup and styles for your interface rather than adapting the interface to a ready-made component. This makes it possible to maintain a consistent look with the rest of the product's screens.

What the client receives upon completion of the implementation

The implementation ends not with a demonstration of a working table, but with a set of artifacts that your team can use to develop it without us. Below is exactly what we hand over.

  • Table configuration — a description of columns, data types, sorting, filters, and groupings in a declarative form. A new column is added by editing a single description rather than rewriting the rendering logic.
  • State model schema — a map of where sorting, pagination, row selection, and expanded groups live: what is in the page URL, what is in local state, and what is sent to the server. It shows why a filter is not reset on navigation and how to reproduce the table state via a link.
  • Column extension guidelines — a step-by-step procedure: where to declare a column, how to wire up server-side sorting by it, and which checks to run. It is designed for a developer seeing the project for the first time.
  • Integration documentation — exchange contracts with your API: the request format when changing pages and filters, the response structure, behavior on an empty result and on error, cursor-based or page-based pagination.
  • Team instructions — how to run the project locally, where the test data is stored, which commands run the checks and the build, and what to look at when the numbers in the table and in the export diverge.
  • A set of checks — tests for sorting, filtering, pagination, and export, including edge cases: an empty response, the last incomplete page, and resetting filters.
  • A list of known limitations — an honest list of what was deliberately left out of scope and which areas should be revisited as data grows.

Each artifact is tied to the working code rather than existing separately from it. If in six months there are twice as many columns, the extension follows the guidelines — without reaching out to the authors of the original version.

How server-side pagination differs from client-side pagination in practice

Client-side pagination keeps the entire set of rows in the browser's memory: the table fetches the data once and then slices it itself, instantly switching pages without requests to the server.

As long as there are hundreds or thousands of rows, this is the simplest and fastest approach — sorting and filtering also fall to the client.

The problem begins as the data grows: each new record increases both the size of the dataset and the time to first render, and the load falls on the user's device rather than on the server.

Server-side pagination flips the model: the browser requests only the current page, while filtering, sorting, and counting the total number of rows are handled by the database.

The load on the server becomes predictable — each page transition takes one compact request instead of fetching the entire array.

That is exactly why, as data grows, the server-side model remains responsive where the client-side one already hits the limits of memory and rendering time.

Choosing a model is a question of where the data lives and how it grows. Client-side pagination is appropriate for reference lists, admin tables with a few thousand rows, and reports that rarely change.

Server-side is for event journals, orders, logs, and any datasets that are constantly being added to and measured in tens of thousands of rows or more.

In practice, the models are often combined: the server returns a page, while sorting within it and quick search across the loaded chunk of the table are done on the client. This preserves instant response to user actions and keeps the load on the server from growing.

We analyze a specific dataset and its dynamics, after which we settle on a model — otherwise the table either lags at the start or hits its ceiling at the very first sign of growth.

Case study: an 80,000-row table stopped freezing during filtering

The client came with a working warehouse accounting table: 80,000 rows, 14 columns, filters by status, dates, and counterparty.

On every character entered in the search field, the interface froze for 4-6 seconds — React re-rendered all rows at once, and filtering ran over the full array in memory.

Users had gotten used to "click and wait," and performed some operations in Excel because the response there was faster. Support was receiving 15-20 tickets a week with the wording "the table is not responding."

We rewrote the data layer and rendering with TanStack Table. We moved the filtering and sorting logic to server-side pagination, leaving only a virtualized list in the browser — 30-40 rows live in the DOM instead of 80,000.

We keep the filter state in the URL so that a link to a specific selection can be sent to a colleague.

The size of the table code itself shrank from ~2400 to ~900 lines: the manual synchronization of sorting, row selection, and pagination that used to be maintained by hand was gone.

Metric Before After
Response to filter input 4-6 s 120-200 ms
Interface freezes regularly during filtering not reproducible
Rows in DOM 80 000 30-40
Table code ~2400 lines ~900 lines
Support tickets 15-20 per week 1-2 per month

A month after rollout, the client's team added two more columns and a new filter — without changes to the table core, just by describing the configuration. That was the main result: extending the table became cheaper than maintaining the old one.

Common technical concerns before starting work

Before the start, almost every team asks the same set of questions — they concern not the library itself, but how it will coexist with an already working product. Below are answers to the five concerns that most often come up on technical calls.

Compatibility: will it work with our current stack?

TanStack Table is a headless core: it handles sorting, filtering, grouping, pagination, and row virtualization, but does not impose markup or styles.

That is why the table integrates into any current interface — React, Vue, Svelte, Solid — and does not conflict with your design system. We connect it to existing data sources through your transport layer, without rewriting the backend.

Migration: what will happen to the old table and its data?

We migrate gradually: first we stand up the new table alongside the old one on the same dataset, compare queries, sorting, and aggregates row by row. Only after the discrepancies are zero do we switch the traffic.

The state of filters and columns can be saved in the URL or local storage — the user does not lose context during navigation.

Code support: who will maintain it after handover?

We hand over a repository with a readable structure: column configuration, cells, and hooks are moved into separate modules, and the logic is not smeared across components. We write documentation on extension — how to add a column, filter, or data source without editing the core. After that, either we maintain it, or your team runs it independently.

Testing: how do we make sure the table won't break on real data?

We cover the critical paths with checks: sorting, filtering, pagination, row selection, and edge cases — empty datasets, large volumes, corrupted values. We run it on your real exports, not on synthetic data, to catch anomalies before release.

Implementation timeline: how long will it take?

We show the first working version with basic operations early — then we build up filters, grouping, and virtualization in iterations. The exact schedule depends on the number of columns, sources, and access rules, so we fix the stages after analyzing your task.

Describe your current table and requirements — we will come back with an estimate, a migration plan, and the scope of checks.

Let's discuss your task and come back with an estimate and a plan

The first conversation takes 30-40 minutes and does not require you to provide a technical specification. It is enough to describe what problem the tables solve today: how many rows and columns are in the real data, who filters them and how often, and what happens during export.

This is enough to understand the class of solution — row virtualization, server-side pagination, database-side aggregates — and to avoid over-engineering.

We will separately discuss data preparation: where the records come from, in what form they are currently stored, whether there are reference data sets and role-based access rights.

Often the bottleneck is not the table itself, but how the query is structured on the backend — this becomes clear during the very first review.

After the conversation, we send an estimate of the work and an implementation plan. These include:

  • the data schema and the sources we will need to work with;
  • a list of scenarios: sorting, filters, grouping, editing, export;
  • requirements for the server side — pagination, aggregates, caching of heavy queries;
  • project stages with the delivery order and the points where you see an intermediate result;
  • the team composition and roles on the project;
  • risks: data volume, unstable sources, limitations of the current stack;
  • the acceptance format — on which data and scenarios we verify the result.

The estimate is based on your real volumes, not on averaged assumptions, so after it the implementation plan is not rewritten halfway through.

If part of the data is not yet digitized or the sources are not ready, we record that as well — either we include preparation as a separate stage, or we propose a solution that works with the current exports.

Describe the task in any convenient form — a link to a prototype, a list of scenarios, or an example of a table you are working with right now. We will come back with an estimate and an implementation plan that you can use to make a decision.

Our competencies:

Latest works

  • B2B ADVANCE company website development
    B2B ADVANCE company website development
    1542
  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1393
  • Website development for BELFINGROUP
    Website development for BELFINGROUP
    1081
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1368
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1139
  • Website development for FIXPER company
    Website development for FIXPER company
    1060