Create a React JS Table Component

Managing data is at the heart of almost every React application I have built over the last eight years.

Whether I was working on a financial dashboard for a New York hedge fund or a logistics tracker for a shipping company in Chicago, tables were always the centerpiece.

In this tutorial, I will show you exactly how to build a robust React JS table component from scratch and how to use modern libraries to handle complex data.

By the end of this guide, you will be able to display, sort, and filter data like a seasoned pro.

Custom Table Component in React

In my experience, standard HTML tables are fine for simple static content, but they fall apart in modern web apps.

React allows us to turn these static grids into dynamic components that react instantly to user input.

Using a component-based approach makes your code reusable across different projects, saving you dozens of hours in the long run.

Method 1: Build a Dynamic Table from Scratch

When I first started with React, I preferred building everything from scratch to maintain total control over the styling and behavior.

In this example, we will build a “US Employee Directory” table that displays names, roles, and office locations.

Here is the complete code for a functional React table. I have kept the logic clean and used modern functional components with hooks.

import React from 'react';

// Sample data representing a US-based corporate team
const employeeData = [
  { id: 1, name: 'John Miller', role: 'Software Engineer', location: 'San Francisco, CA', salary: '$125,000' },
  { id: 2, name: 'Sarah Jenkins', role: 'Product Manager', location: 'Austin, TX', salary: '$140,000' },
  { id: 3, name: 'Michael Chen', role: 'UX Designer', location: 'Seattle, WA', salary: '$115,000' },
  { id: 4, name: 'Emily Davis', role: 'Data Scientist', location: 'Boston, MA', salary: '$135,000' },
  { id: 5, name: 'Robert Wilson', role: 'Marketing Director', location: 'New York, NY', salary: '$155,000' },
];

const EmployeeTable = () => {
  return (
    <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
      <h2 style={{ borderBottom: '2px solid #333', paddingBottom: '10px' }}>
        US Corporate Employee Directory
      </h2>
      <table style={{ width: '100%', borderCollapse: 'collapse', marginTop: '20px' }}>
        <thead>
          <tr style={{ backgroundColor: '#f4f4f4', textAlign: 'left' }}>
            <th style={tableHeaderStyle}>ID</th>
            <th style={tableHeaderStyle}>Name</th>
            <th style={tableHeaderStyle}>Role</th>
            <th style={tableHeaderStyle}>Office Location</th>
            <th style={tableHeaderStyle}>Annual Salary</th>
          </tr>
        </thead>
        <tbody>
          {employeeData.map((employee) => (
            <tr key={employee.id} style={{ borderBottom: '1px solid #ddd' }}>
              <td style={tableCellStyle}>{employee.id}</td>
              <td style={tableCellStyle}>{employee.name}</td>
              <td style={tableCellStyle}>{employee.role}</td>
              <td style={tableCellStyle}>{employee.location}</td>
              <td style={tableCellStyle}>{employee.salary}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

const tableHeaderStyle = {
  padding: '12px',
  border: '1px solid #ddd',
  fontWeight: 'bold',
};

const tableCellStyle = {
  padding: '12px',
  border: '1px solid #ddd',
};

export default EmployeeTable;

I executed the above example code and added the screenshot below.

React JS Table Component

I used the .map() function to iterate through the employeeData array. This is the most efficient way to generate rows dynamically in React.

Notice the key prop on the <tr> tag; I always use a unique ID to help React track which items have changed, which prevents rendering bugs.

Method 2: Add Search and Filter Functionality

A table isn’t very useful if you have hundreds of rows and no way to find what you need.

I often implement a search bar at the top of my tables to allow users to filter by name or location instantly.

In the following example, we will add a search input that filters our US employee list in real-time.

import React, { useState } from 'react';

const initialData = [
  { id: 1, name: 'John Miller', role: 'Software Engineer', location: 'San Francisco, CA' },
  { id: 2, name: 'Sarah Jenkins', role: 'Product Manager', location: 'Austin, TX' },
  { id: 3, name: 'Michael Chen', role: 'UX Designer', location: 'Seattle, WA' },
  { id: 4, name: 'Emily Davis', role: 'Data Scientist', location: 'Boston, MA' },
  { id: 5, name: 'Robert Wilson', role: 'Marketing Director', location: 'New York, NY' },
];

const SearchableTable = () => {
  const [searchTerm, setSearchTerm] = useState('');

  // Filter logic based on user input
  const filteredEmployees = initialData.filter((item) =>
    item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
    item.location.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div style={{ padding: '20px' }}>
      <input
        type="text"
        placeholder="Search by name or city..."
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        style={{
          padding: '10px',
          width: '300px',
          marginBottom: '20px',
          borderRadius: '4px',
          border: '1px solid #ccc'
        }}
      />
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead>
          <tr style={{ backgroundColor: '#007bff', color: 'white' }}>
            <th style={cellStyle}>Name</th>
            <th style={cellStyle}>Role</th>
            <th style={cellStyle}>Location</th>
          </tr>
        </thead>
        <tbody>
          {filteredEmployees.length > 0 ? (
            filteredEmployees.map((val) => (
              <tr key={val.id}>
                <td style={cellStyle}>{val.name}</td>
                <td style={cellStyle}>{val.role}</td>
                <td style={cellStyle}>{val.location}</td>
              </tr>
            ))
          ) : (
            <tr>
              <td colSpan="3" style={{ textAlign: 'center', padding: '20px' }}>No matches found.</td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
};

const cellStyle = {
  padding: '12px',
  border: '1px solid #ddd',
  textAlign: 'left'
};

export default SearchableTable;

I executed the above example code and added the screenshot below.

Create React JS Table Component

I always use .toLowerCase() on both the search string and the data field. This ensures the search is case-insensitive, providing a much better user experience for people quickly typing names.

Method 3: Implement Sorting Logic

In many US-based enterprise applications, users expect to click a column header to sort the data alphabetically or numerically.

I find that building a custom sorting hook makes the table feel professional and high-end.

Here is how I implement a sortable table for “US Real Estate Listings.”

import React, { useState } from 'react';

const propertyData = [
  { id: 1, city: 'Denver', state: 'CO', price: 550000 },
  { id: 2, city: 'Miami', state: 'FL', price: 820000 },
  { id: 3, city: 'Phoenix', state: 'AZ', price: 450000 },
  { id: 4, city: 'Nashville', state: 'TN', price: 610000 },
];

const SortablePropertyTable = () => {
  const [data, setData] = useState(propertyData);
  const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' });

  const sortTable = (key) => {
    let direction = 'asc';
    if (sortConfig.key === key && sortConfig.direction === 'asc') {
      direction = 'desc';
    }

    const sortedData = [...data].sort((a, b) => {
      if (a[key] < b[key]) return direction === 'asc' ? -1 : 1;
      if (a[key] > b[key]) return direction === 'asc' ? 1 : -1;
      return 0;
    });

    setData(sortedData);
    setSortConfig({ key, direction });
  };

  return (
    <div style={{ padding: '20px' }}>
      <h3>US Real Estate Market - Sortable View</h3>
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead>
          <tr>
            <th onClick={() => sortTable('city')} style={headerPointer}>City ↕</th>
            <th onClick={() => sortTable('state')} style={headerPointer}>State ↕</th>
            <th onClick={() => sortTable('price')} style={headerPointer}>Price ↕</th>
          </tr>
        </thead>
        <tbody>
          {data.map((item) => (
            <tr key={item.id}>
              <td style={cellStyle}>{item.city}</td>
              <td style={cellStyle}>{item.state}</td>
              <td style={cellStyle}>${item.price.toLocaleString()}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

const headerPointer = {
  cursor: 'pointer',
  padding: '12px',
  backgroundColor: '#f8f9fa',
  border: '1px solid #ddd'
};

const cellStyle = {
  padding: '12px',
  border: '1px solid #ddd'
};

export default SortablePropertyTable;

I executed the above example code and added the screenshot below.

Create a React JS Table Component

Method 4: Use TanStack Table (React Table Library)

When the requirements get complex, like handling pagination, windowing, or column resizing, I stop building from scratch.

I almost exclusively use TanStack Table (formerly known as React Table). It is a “headless” UI library.

This means it handles all the logic, but lets you keep full control over your CSS and HTML structure.

It doesn’t dictate your design. You can make it look like Bootstrap, Tailwind, or your own custom CSS.

It is extremely lightweight because it doesn’t ship with any pre-made UI components.

Handle Large Datasets with Virtualization

If you are dealing with 10,000+ rows (common in US healthcare or census data apps), your browser will lag.

In these cases, I use “Virtualization.” This technique renders only the rows currently visible on the screen.

Using a library like react-window alongside your table component is the best way to maintain 60 FPS performance.

Style Your Table for a Professional Look

I’ve found that a clean, spaced-out design works best for American corporate users.

Avoid using too many colors. Stick to a simple “zebra-stripe” pattern where every other row has a light gray background.

This makes it significantly easier for the human eye to follow a single row across multiple columns.

Building a table in React JS is a fundamental skill that every developer should master.

Whether you build a simple static grid or a complex sortable system, the key is to keep your data and logic separate.

You may also read:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.