ReviseAlgo Logo

Machine Coding

Data Table

Master building a Data Table in React, covering column sorting, search filtering, pagination controls, and multi-row selection with checkboxes.

Last Updated: July 15, 2026 14 min read

1. Learning Objectives

In this challenge, you will build a feature-rich Data Table component. By the end of this guide, you will be able to:

  • Sort table columns in ascending and descending order by clicking column headers.
  • Implement a global search filter that matches across multiple columns.
  • Build client-side pagination with page navigation controls.
  • Add multi-row selection using checkboxes with a "select all" toggle.
  • Derive displayed data by chaining filter, sort, and slice operations.

2. Overview

A Data Table is one of the most commonly asked machine coding challenges. It tests your ability to compose multiple data transformations — filtering, sorting, and slicing — into a single rendering pipeline without mutating the original data source.

3. Why This Challenge Matters

Data tables teach fundamental data pipeline patterns:

  • Composable Transformations: Chaining .filter().sort().slice() mirrors real-world data pipeline patterns used in dashboards, admin panels, and reporting tools.
  • Derived State Mastery: The displayed rows are never stored in state; they are computed on every render from the raw data, search query, sort configuration, and current page.

4. Real-World Analogy

Think of a Data Table like a librarian organizing a card catalog:

  • The Full Catalog: All card entries stored in a drawer — this is the raw data array in state.
  • Search: Pulling out only cards that match a keyword — this is the .filter() step.
  • Sort: Arranging the pulled cards alphabetically by title or by date — this is the .sort() step.
  • Pagination: Placing only 10 cards on the display desk at a time — this is the .slice() step.

5. Core Concepts

Below is a comparison of storing processed data in state versus computing it during render:

Property Storing Processed Data (Anti-pattern) Computing During Render (Recommended)
State Variables filteredData, sortedData, pagedData — three separate state variables. Only data, search, sortConfig, page in state. Derived values computed inline.
Synchronization Risk High. Changing the search query requires updating all three derived states in the correct order. None. The pipeline re-runs automatically when any input state changes.
Performance Appears faster but risks stale data and bugs. Use useMemo to cache expensive computations if needed.

6. Syntax & API Reference

This example shows the data transformation pipeline — filter, sort, then paginate:

7. Visual Diagram

This diagram shows the data transformation pipeline:

8. Live Example — Full Working Code

Below is a complete HTML page demonstrating a data table with sort, search, pagination, and row selection:

What just happened? The raw USERS array is never mutated. The transformation pipeline — filter by search, sort by column, slice by page — runs inside useMemo on every render. Clicking a column header toggles its sort direction, the search input filters across all columns, and the pagination controls slice the results into pages.

9. Interactive Playground

Try It Yourself Challenges:

  1. Add a dropdown filter for the "Role" column that lets users filter by Admin, Editor, or Viewer.
  2. Add a "rows per page" selector that lets the user choose 5, 10, or 20 rows per page.

10. Common Mistakes

Mistake Why it happens Wrong Correct
Sorting the original data array Using data.sort() mutates the original array in place, causing unpredictable renders and bugs when trying to "unsort". data.sort((a, b) => ...); [...data].sort((a, b) => ...);
Not resetting page on search Typing a search query while on page 3 shows an empty page because the filtered result may have fewer than 3 pages. setSearch(val);
// page stays at 3
setSearch(val);
setPage(1);

11. Best Practices

  • Never mutate the source array: Always spread or slice before sorting: [...data].sort().
  • Reset page on filter/sort changes: When the search query changes or the sort column changes, reset the current page to 1.
  • Use useMemo for expensive pipelines: Wrap the filter + sort pipeline in useMemo to avoid recomputing on unrelated state changes.
  • Use Set for selections: A Set provides O(1) lookup for .has(id), making it more efficient than arrays for selection tracking.

12. Browser Compatibility/Requirements

This project uses standard JavaScript array methods and runs on all modern browsers.

13. Interview Questions

Q1: Why should filter, sort, and paginate be derived computations rather than separate state variables?

Answer: Storing derived data in separate state variables creates synchronization risks. If the raw data, search query, or sort configuration changes, all derived states must be updated in the correct order. Computing them inline from the source data ensures they are always consistent and eliminates an entire class of bugs.

Q2: How would you handle server-side sorting and pagination instead of client-side?

Answer: Instead of processing data locally, send the sort column, sort direction, page number, and search query as query parameters to the API. The server returns only the relevant page of pre-sorted, pre-filtered results. State variables still track the same values, but they are used to construct API requests rather than to transform local data.

14. Debugging Exercise

Identify why clicking a column header to sort corrupts the original data and breaks the search filter:

View Solution

Diagnosis: data.sort() mutates the original array in place. Since React compares by reference, it may not detect changes. The original ordering is permanently lost, so features like "unsort" or search (which depend on a stable source) break.

Fix: Create a copy before sorting:

15. Practice Exercises

Exercise 1: Inline cell editing

Make table cells editable. Double-clicking a cell should turn it into an input field. Pressing Enter saves the change and pressing Escape cancels it.

16. Scenario-Based Challenge

The server-side data table challenge:

Your table now has 100,000 rows. Client-side sorting and filtering is too slow. Redesign the component to delegate sorting, filtering, and pagination to a REST API. Describe what query parameters you would send, how you would handle loading states between page changes, and how you would debounce the search input to avoid excessive API calls.

17. Quick Quiz

Q1: Why must you call setPage(1) when the search query changes?

A) Because page numbers must always start at 1

B) Because the filtered result set may have fewer pages than the current page number

C) Because React requires sequential state updates

Answer: B — If you are on page 3 and the new search returns only 2 results, page 3 does not exist. Resetting to page 1 prevents showing an empty page.

18. Summary & Key Takeaways

  • Build data tables using a composable pipeline: filter → sort → slice.
  • Never mutate the source data array. Always spread before sorting.
  • Reset the page number whenever the search query or sort configuration changes.
  • Use useMemo to cache expensive transformation pipelines.
  • Use a Set for efficient multi-row selection tracking.

19. Cheat Sheet

Operation Syntax Pattern
Safe sort [...data].sort((a, b) => ...)
Global search data.filter(r => Object.values(r).some(v => String(v).includes(q)))
Paginate data.slice((page - 1) * perPage, page * perPage)
Toggle Set next.has(id) ? next.delete(id) : next.add(id)
---