How to Build a Custom Table Component in React MUI

I have found that tables are often the most complex yet essential part of any dashboard.

While Material UI (MUI) provides a solid foundation, a “one-size-fits-all” approach rarely works for real-world enterprise applications.

I remember struggling with messy, repetitive table code early in my career until I started building reusable, custom components.

In this tutorial, I will show you exactly how I build flexible, professional tables that handle complex data with ease.

Use MUI for Custom Tables

MUI offers a robust set of components like Table, TableBody, and TableCell that follow Google’s Material Design.

It saves me hours of CSS work and provides built-in accessibility features that are hard to build from scratch.

Set Up Your React Environment

Before we dive into the code, you need to ensure your environment is ready.

I always start by installing the necessary MUI packages to get access to the styling engine.

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

Method 1: Build a Dynamic Reusable Table

When I build tables for my clients, I never hard-code the columns inside the main component.

Instead, I pass a configuration array. This makes the component incredibly easy to reuse across different pages.

Here is the full code for a reusable table that displays financial data for US-based tech companies.

import React from 'react';
import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  Typography
} from '@mui/material';

// Custom component to handle dynamic headers and data
const CustomDataTable = ({ columns, data }) => {
  return (
    <TableContainer component={Paper} sx={{ marginTop: 4, boxShadow: 3 }}>
      <Table sx={{ minWidth: 650 }} aria-label="customized table">
        <TableHead sx={{ backgroundColor: '#1976d2' }}>
          <TableRow>
            {columns.map((column) => (
              <TableCell 
                key={column.id} 
                sx={{ color: '#fff', fontWeight: 'bold', fontSize: '1.1rem' }}
              >
                {column.label}
              </TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {data.map((row, index) => (
            <TableRow 
              key={index} 
              sx={{ '&:nth-of-type(odd)': { backgroundColor: '#f5f5f5' } }}
            >
              {columns.map((column) => (
                <TableCell key={column.id}>
                  {row[column.id]}
                </TableCell>
              ))}
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
};

// Example Usage with US Tech Stock Data
const App = () => {
  const columns = [
    { id: 'ticker', label: 'Stock Ticker' },
    { id: 'company', label: 'Company Name' },
    { id: 'price', label: 'Current Price (USD)' },
    { id: 'marketCap', label: 'Market Cap' },
    { id: 'location', label: 'HQ Location' },
  ];

  const data = [
    { ticker: 'AAPL', company: 'Apple Inc.', price: '$185.92', marketCap: '2.89T', location: 'Cupertino, CA' },
    { ticker: 'MSFT', company: 'Microsoft Corp.', price: '$402.56', marketCap: '3.01T', location: 'Redmond, WA' },
    { ticker: 'NVDA', company: 'NVIDIA Corp.', price: '$726.13', marketCap: '1.79T', location: 'Santa Clara, CA' },
    { ticker: 'AMZN', company: 'Amazon.com Inc.', price: '$169.51', marketCap: '1.76T', location: 'Seattle, WA' },
    { ticker: 'GOOGL', company: 'Alphabet Inc.', price: '$147.22', marketCap: '1.84T', location: 'Mountain View, CA' },
  ];

  return (
    <div style={{ padding: '40px' }}>
      <Typography variant="h4" gutterBottom>
        US Tech Giants - Market Overview
      </Typography>
      <CustomDataTable columns={columns} data={data} />
    </div>
  );
};

export default App;

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

Custom Table Component in React MUI

In this method, I used the sx prop to apply striped rows, which I find significantly improves readability for large datasets.

Method 2: Add Sorting and Pagination

In professional applications, you rarely show all data at once. You need pagination and the ability to sort.

I have implemented this hundreds of times to help users navigate through thousands of payroll records or shipping logs.

Below is the implementation using MUI’s TablePagination and a custom sorting hook logic.

import React, { useState } from 'react';
import {
  Table, TableBody, TableCell, TableContainer, TableHead, 
  TableRow, Paper, TablePagination, TableSortLabel, Box
} from '@mui/material';

const US_EMPLOYEE_DATA = [
  { id: 1, name: 'James Smith', role: 'Software Engineer', state: 'Texas', salary: 125000 },
  { id: 2, name: 'Maria Garcia', role: 'Project Manager', state: 'Florida', salary: 110000 },
  { id: 3, name: 'Robert Johnson', role: 'Data Scientist', state: 'New York', salary: 140000 },
  { id: 4, name: 'Linda Williams', role: 'UX Designer', state: 'Washington', salary: 115000 },
  { id: 5, name: 'Michael Brown', role: 'DevOps Engineer', state: 'Colorado', salary: 130000 },
  { id: 6, name: 'Patricia Jones', role: 'Product Owner', state: 'Illinois', salary: 135000 },
];

const EnhancedTable = () => {
  const [order, setOrder] = useState('asc');
  const [orderBy, setOrderBy] = useState('salary');
  const [page, setPage] = useState(0);
  const [rowsPerPage, setRowsPerPage] = useState(5);

  const handleRequestSort = (property) => {
    const isAsc = orderBy === property && order === 'asc';
    setOrder(isAsc ? 'desc' : 'asc');
    setOrderBy(property);
  };

  const handleChangePage = (event, newPage) => {
    setPage(newPage);
  };

  const sortedData = [...US_EMPLOYEE_DATA].sort((a, b) => {
    if (order === 'asc') return a[orderBy] < b[orderBy] ? -1 : 1;
    return a[orderBy] > b[orderBy] ? -1 : 1;
  });

  return (
    <Box sx={{ width: '100%', p: 3 }}>
      <Paper sx={{ width: '100%', mb: 2 }}>
        <TableContainer>
          <Table>
            <TableHead>
              <TableRow>
                <TableCell>Name</TableCell>
                <TableCell>Role</TableCell>
                <TableCell>State</TableCell>
                <TableCell sortDirection={orderBy === 'salary' ? order : false}>
                  <TableSortLabel
                    active={orderBy === 'salary'}
                    direction={orderBy === 'salary' ? order : 'asc'}
                    onClick={() => handleRequestSort('salary')}
                  >
                    Salary (USD)
                  </TableSortLabel>
                </TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {sortedData
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map((row) => (
                  <TableRow key={row.id}>
                    <TableCell>{row.name}</TableCell>
                    <TableCell>{row.role}</TableCell>
                    <TableCell>{row.state}</TableCell>
                    <TableCell>${row.salary.toLocaleString()}</TableCell>
                  </TableRow>
                ))}
            </TableBody>
          </Table>
        </TableContainer>
        <TablePagination
          rowsPerPageOptions={[5, 10]}
          component="div"
          count={US_EMPLOYEE_DATA.length}
          rowsPerPage={rowsPerPage}
          page={page}
          onPageChange={handleChangePage}
        />
      </Paper>
    </Box>
  );
};

export default EnhancedTable;

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

Build a Custom Table Component in React MUI

I personally prefer using toLocaleString() for currency because it ensures the data looks familiar to users in the United States.

Method 3: Conditional Styling for Data Highlights

Sometimes, you need to draw attention to specific cells, like negative balances or high-priority tickets.

In my experience, using background colors or icons inside cells is the most effective way to alert a user.

In this example, we will style a “Tax Filing Status” table for different US states.

import React from 'react';
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Chip } from '@mui/material';

const TAX_DATA = [
  { state: 'Delaware', type: 'Corporate', status: 'Completed', amount: '$4,500' },
  { state: 'Nevada', type: 'Sales Tax', status: 'Pending', amount: '$12,200' },
  { state: 'Wyoming', type: 'Franchise', status: 'Overdue', amount: '$850' },
  { state: 'Texas', type: 'Property', status: 'Completed', amount: '$15,000' },
];

const StatusTable = () => {
  const getStatusColor = (status) => {
    switch (status) {
      case 'Completed': return 'success';
      case 'Pending': return 'warning';
      case 'Overdue': return 'error';
      default: return 'default';
    }
  };

  return (
    <TableContainer component={Paper} sx={{ maxWidth: 800, margin: 'auto' }}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>US State</TableCell>
            <TableCell>Tax Type</TableCell>
            <TableCell align="center">Status</TableCell>
            <TableCell align="right">Amount Due</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {TAX_DATA.map((row) => (
            <TableRow key={row.state}>
              <TableCell>{row.state}</TableCell>
              <TableCell>{row.type}</TableCell>
              <TableCell align="center">
                <Chip label={row.status} color={getStatusColor(row.status)} variant="outlined" />
              </TableCell>
              <TableCell align="right">{row.amount}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
};

export default StatusTable;

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

Build Custom Table Component in React MUI

I used the Chip component here because it provides a modern, clean look compared to just changing the text color.

Best Practices for MUI Tables

Over the years, I’ve learned that performance matters as much as design.

If you have more than 100 rows, I always recommend using virtualization or server-side pagination.

Also, keep your table responsive. MUI tables can break on mobile if you have too many columns.

I usually wrap my TableContainer in a Box with overflowX: ‘auto’ to prevent layout breaking on iPhones or Android devices.

Building a custom table in React MUI is all about balancing flexibility with clean code.

In this guide, I showed you how to build a dynamic table, add sorting, and apply conditional styling.

Whether you are building a simple list or a complex financial dashboard, these methods will serve you well.

You may also like to read the other tutorials:

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.