How to Design Data Tables for Complex Web Applications

Dashboard with a data grid showing rows, columns, and filter controls

Data tables are among the most functionally dense UI elements in web applications. When they work well, users can sort, filter, and act on large datasets with minimal friction. When they are built without intentional patterns, they become the part of the application that users avoid, work around with exports, or complain about in feedback sessions. The failure mode is predictable: a table that works fine at 50 rows becomes unusable at 500, and a table that handles read-only viewing becomes confusing the moment you add editing or bulk actions.

This guide covers the patterns that make data tables functional at scale, including the decisions most teams defer until they become problems.

Column Structure: Start With the User's Primary Task

Before deciding which columns to include, identify what question the user is trying to answer with this table. A user reviewing invoice status asks "which invoices are overdue and for how much?" A user managing user accounts asks "who has not logged in recently, and what is their role?" The table's column selection and default sort order should make that primary question answerable without any interaction.

Practical column structure rules:

  • Lead with the columns most relevant to the primary task in the first two or three positions
  • Put identifier columns (name, ID, reference number) first - users scan these to orient themselves in the data
  • Reserve the rightmost column for action controls (edit, delete, view details) if actions are per-row
  • Avoid including more than 8-10 columns by default; offer additional columns via a column picker for users who need them

Column width management is consistently underbuilt. Columns that contain unpredictable-length content (names, descriptions, email addresses) should truncate with a visible tooltip on hover. Fixed-width columns for dates, status badges, and numeric values prevent the layout shift that happens when variable content reflows.

spreadsheet data rows columns organized
Photo by Maël BALLAND on Pexels

Sorting: Make State Explicit and Predictable

Single-column sorting is standard and expected. Multi-column sorting - where a secondary sort applies when the primary sort has ties - is genuinely useful for relational data but needs explicit UI treatment to be discoverable. If you support multi-column sorting, show the sort priority as numbered badges on the column headers.

For any sort state:

  • The currently sorted column should have a persistent visual indicator (not just on hover)
  • The sort direction (ascending/descending) should be visible in the header
  • A default sort state should exist when the table loads; "no sort" is confusing for most data types

One decision worth making explicitly: whether the sort indicator changes on first click (toggle from default) or whether it always starts ascending. Users do not have a consistent mental model of this behavior across products. Document your choice in your design system and implement it consistently across all tables in the application.

Filtering: Contextual vs. Panel-Based Approaches

Two filtering patterns dominate complex web applications: column-level filters and a separate filter panel.

Column-level filters sit in or near the column header and apply to a single column. They work well for simple equality or range filters on known data types (status badges with a dropdown, date ranges with a picker, numeric ranges). They fail when the filter logic is complex, when multiple columns interact, or when users need to save and reuse filter combinations.

Filter panels appear above or beside the table as a collapsible form. They handle complex multi-column filter logic better and are easier to scan when many filters are active. The trade-off is that they require more visual real estate and a separate interaction to open.

A practical hybrid: start with column-level filters for the most common filter columns (status, date range, owner). Add a "More filters" panel for additional criteria. Surface the active filter count as a badge so users know filters are applied even when the panel is collapsed.

Filter state should persist within a session. If a user applies filters and navigates away, returning to the table should restore the filter state. Clearing filters should be one action, not column-by-column.

Pagination vs. Virtual Scrolling

For tables with under 10,000 rows, pagination with configurable page size (25, 50, 100 rows per page) is the safer default. It has predictable scroll behavior, works reliably with server-side data fetching, and is accessible without additional implementation work.

Virtual scrolling (rendering only the rows visible in the viewport) makes sense for very large datasets where navigating through pages is genuinely cumbersome. The implementation complexity is significant: maintaining scroll position on data updates, handling keyboard navigation across virtualized rows, and making the content accessible to screen readers all require careful work. Libraries like TanStack Table handle much of this complexity for React and other frameworks.

The case against virtual scrolling unless you need it: it is harder to select all rows when they are not all rendered, users cannot jump to a specific row by scrolling to a known position, and print/export behavior becomes complicated.

dashboard interface data screen monitor
Photo by Rubenstein Rebello on Pexels

Row Selection and Bulk Actions

Row selection patterns follow a consistent model: a checkbox column at the left edge of the table, a "select all" checkbox in the column header, and a bulk action toolbar that appears (or becomes active) when rows are selected.

The "select all" behavior needs a specific decision: does "select all" select all visible rows on the current page, or all rows matching the current filter across all pages? For most data management workflows, users need all rows in the filter set, not just the current page. If your table supports this, display the count of all matching rows and offer a prompt: "All 47 rows on this page are selected. Select all 312 rows matching your filter."

Bulk action toolbars should:

  • Appear at the top of the table when any rows are selected
  • Show the count of selected rows
  • Include only the actions that apply to all selected row types (if row type matters)
  • Have a confirmation step before irreversible bulk actions (delete, archive)

Inline Editing: When It Adds Value and When It Complicates

Inline editing - clicking directly in a table cell to edit it - works well when the edit interaction is simple (changing a status dropdown, editing a short text field) and when users need to edit many rows quickly. It fails when the edit requires complex validation, depends on other field values, or involves choosing from a large option set.

For fields that do require a form (multi-field edits, complex validation), a slide-over panel or modal that opens from the row is cleaner than trying to fit the edit UI into the row itself.

If inline editing is enabled:

  • Make editable cells visually distinct from read-only cells (a subtle border or background change on hover)
  • Show save/cancel controls on the changed row, not globally
  • Handle optimistic updates with visible error states if the server save fails

"The tables we build for data-heavy client applications are often where users spend most of their day. Getting the edit pattern wrong means they're fighting the interface every hour. Getting it right means they stop thinking about the interface at all." - Dennis Traina, founder of 137Foundry

Responsive Behavior: What Tables Do on Small Screens

Standard data tables with 6+ columns do not work on mobile screens in their desktop form. Three approaches handle this:

Horizontal scrolling: the table maintains its column structure but scrolls horizontally. Works when users understand they need to scroll (indicate this with a visible scrollbar or a shadow edge) and when column count is manageable.

Column prioritization: hide lower-priority columns at smaller breakpoints and add them to an expandable row detail. The user sees the most important columns in the viewport and taps to see the rest.

Card layout at small breakpoints: the table becomes a list of cards below a certain screen width, each card showing the row data in a vertical key-value format. This is the most readable on small screens but the most expensive to implement.

For internal web applications where mobile use is predictable and controlled (employees using company devices, admin panels), horizontal scrolling with a locked identifier column (position: sticky) is often sufficient. Consumer-facing applications need more consideration.

Accessibility Basics

React and other component frameworks do not automatically produce accessible tables. The underlying HTML semantics need attention regardless of what library you use.

Key requirements for accessible data tables:

  • Use proper <table>, <thead>, <tbody>, <th>, and <td> elements, not divs styled to look like a table
  • <th> elements need scope="col" or scope="row" attributes for screen reader association
  • Column sorting triggers should be buttons (not just click handlers on divs) and communicate sort state via aria-sort
  • Row selection checkboxes need aria-label values that include the row identifier ("Select invoice INV-0042")

MDN has comprehensive table accessibility documentation, and W3C publishes the technical standards that screen readers implement. Both are worth referencing before finalizing your table implementation.

keyboard accessibility navigation screen tablet
Photo by TeeFarm on Pixabay

Choosing a Library vs. Building Custom

AG Grid and TanStack Table represent the two ends of the library spectrum. AG Grid is a full-featured data grid with virtualization, filtering, sorting, grouping, and export built in - it handles most enterprise table requirements out of the box. TanStack Table is a headless utility that handles state and logic while you bring the rendering; it requires more implementation work but integrates with any styling system.

Building a custom table from scratch is justified only when the library solutions genuinely cannot support a specific requirement (unusual interaction patterns, deeply custom rendering, integration with a specialized data source). Most requirements that seem custom are actually supported by the major libraries once you read the documentation carefully.

The data table patterns in your application directly affect how effectively users can work with the underlying data. At 137Foundry, we work with teams on web development projects where complex data grids are a central part of the product. The decisions made early in table design - column structure, filtering approach, edit pattern - tend to compound. Getting them right before the first round of user feedback saves significant rework.

For projects that involve surfacing and managing data from multiple systems, our data integration service connects to these UI patterns directly - a well-designed table is only as useful as the data it is built on.

data table rows filtering sorted interface
Photo by Pixabay on Pexels

Where to Start

If you're designing a new data table or auditing an existing one, work through these questions:

  1. What is the user's primary task? Does the current column order and default sort state support it immediately?
  2. Are filter states persisted within a session, and can all filters be cleared in one action?
  3. Does "select all" select all filtered rows or just the current page, and is the behavior explicitly communicated?
  4. Are all table interactions (sort, filter toggle, row selection, inline edit) keyboard-accessible?
  5. At what row count does the table slow down, and does the pagination or virtualization strategy handle that threshold?

Each of these questions has a clear correct answer. Working through them before implementation, rather than discovering the gaps in user testing, is what separates data tables that users tolerate from ones they actually prefer.

Need help with Web Development?

137Foundry builds custom software, AI integrations, and automation systems for businesses that need real solutions.

Book a Free Consultation View Services