Antd Table Guide: Features, Editable Cells & Fixed Header Explained
Updated on Jun 10, 2025 | 23 min read | 8.13K+ views
Share:
For working professionals
For fresh graduates
More
Updated on Jun 10, 2025 | 23 min read | 8.13K+ views
Share:
Table of Contents
Did you know? In 2025, React reigns as India’s favorite for building sleek, single-page apps—and with it, Ant Design tables have shot up in popularity. Developers are choosing Antd’s powerful Table component to handle complex data like pros, making web apps smarter and faster than ever. |
Ant Design, or Antd, is a popular UI library for React JS developers seeking to craft sleek, professional interfaces without starting from scratch. It offers a comprehensive set of pre-built components that help developers build clean, consistent, and professional-looking interfaces without starting from scratch.
The Antd Table component stands out because it combines simplicity with flexibility. Built for React JS, Ant Design Table customization makes it straightforward to set up, extend, and enhance—from basic data grids to complex interactive tables.
This blog will explore the Antd Table component in detail, providing tips, best practices, and real-world use cases to help you make the most of this powerful tool in your next project.
Ant Design, often called Antd, is a widely used UI framework built specifically for ReactJS applications. It offers a comprehensive set of pre-built components that help developers build clean, consistent, and professional-looking interfaces without starting from scratch. Among its most powerful and versatile components is the Antd Table, a tool designed to display, organize, and manage data efficiently within your React app.
The Antd Table component stands out for its balance of simplicity and extensibility. Features such as column-level sorting, advanced filtering, server-side pagination, and custom row selection logic provide fine-grained control. Its responsive design and support for custom rendering algorithms make it ideal for building performant, interactive data grids across devices.
For those looking to enhance their skill set and learn how to use the Antd Table component more effectively, consider these specialized programs from upGrad:
Also read - What is React? A Complete Overview
Now that we understand what Antd Design is, let’s dive into the Antd Table and explore how to create and set it up within your React app.
Creating an Antd Table in React involves defining data structures with columns and dataSource props for declarative UI control. This setup enables seamless integration with dynamic data, custom rendering logic, and advanced features such as sorting, filtering, and pagination.
Here’s a step-by-step guide to get you started with creating and customizing an Antd Table in your React project:
First, you need to install Ant Design in your React project if you haven’t already:
npm install antd
Then, import the Table component from Antd into your React component file:
import { Table } from 'antd';
To get started, define the structure of your table using two key props:
Here’s a simple example:
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
];
const dataSource = [
{ key: '1', name: 'Alice', age: 32, address: '123 Main St' },
{ key: '2', name: 'Bob', age: 45, address: '456 Park Ave' },
];
<Table columns={columns} dataSource={dataSource} />;
This renders a basic table with three columns and two rows.
You can customize how each column is displayed using the render function. This allows you to display buttons, icons, or even formatted text. Additionally, you can integrate the table with backend services (SQL databases or REST APIs) to make it more dynamic.
For example, to add a button inside a column:
{
title: 'Action',
key: 'action',
render: (text, record) => (
<button onClick={() => alert(`Editing ${record.name}`)}>Edit</button>
),
}
You can also style rows conditionally by using the rowClassName prop or inline styles based on the data content.
Sorting and filtering are easy to implement. For sorting, add a sorter function to the column definition:
{
title: 'Age',
dataIndex: 'age',
key: 'age',
sorter: (a, b) => a.age - b.age,
}
For filtering, define a filters array and an onFilter function:
{
title: 'Age',
dataIndex: 'age',
key: 'age',
filters: [
{ text: 'Under 40', value: 'under40' },
{ text: '40 and above', value: '40plus' },
],
onFilter: (value, record) =>
value === 'under40' ? record.age < 40 : record.age >= 40,
}
This will enable users to sort by age or filter the table based on age ranges.
Grouping Rows in Antd Table
To simulate grouping, you can use a nested data structure or manipulate the data in such a way that you can visually "group" rows together. One effective approach is to structure your data with parent-child relationships and use expandable rows to show grouped data.
Here’s a more detailed example:
Organize your data into groups using a parent-child structure. In this example, we’ll group people by age range.
Use the expandable rows feature to show the grouped data, making the table behave as if the rows are grouped.
Example of Grouping Data:
Let’s consider a data set where we group people by age ranges. Here’s how you might simulate grouping:
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
];
const dataSource = [
{
key: '1',
ageGroup: 'Under 30',
children: [
{ key: '1-1', name: 'Alice', age: 25, address: '123 Main St' },
{ key: '1-2', name: 'Bob', age: 28, address: '456 Park Ave' },
],
},
{
key: '2',
ageGroup: '30 and above',
children: [
{ key: '2-1', name: 'Charlie', age: 32, address: '789 Elm St' },
{ key: '2-2', name: 'David', age: 45, address: '101 Oak St' },
],
},
];
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log('Selected rows:', selectedRows);
},
};
<Table
columns={columns}
dataSource={dataSource}
rowSelection={rowSelection}
expandable={{
expandedRowRender: (record) => (
<Table
columns={columns}
dataSource={record.children}
pagination={false}
showHeader={false}
rowKey="key"
/>
),
rowExpandable: (record) => record.children.length > 0, // Only expand if there are children
}}
/>;
Explanation:
Additional Custom Grouping:
For custom grouping without the expandable feature, you could manually manipulate the data into grouped sections, like this:
const groupedData = [
{ key: '1', group: 'Under 30', name: 'Alice', age: 25, address: '123 Main St' },
{ key: '2', group: 'Under 30', name: 'Bob', age: 28, address: '456 Park Ave' },
{ key: '3', group: '30 and above', name: 'Charlie', age: 32, address: '789 Elm St' },
{ key: '4', group: '30 and above', name: 'David', age: 45, address: '101 Oak St' },
];
<Table
columns={columns}
dataSource={groupedData}
pagination={{ pageSize: 5 }}
rowClassName={(record, index) => {
return record.group ? 'group-row' : '';
}}
/>
Antd allows you to add row selection with checkboxes. Enable this with the rowSelection prop:
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log('Selected rows:', selectedRows);
},
};
<Table rowSelection={rowSelection} columns={columns} dataSource={dataSource} />;
This feature is helpful for bulk actions such as deleting, exporting, or marking multiple rows as read.
In this step, we will cover two things:
1. Adding a Search Box for Filtering Data
First, we need a search box outside the table to dynamically filter rows as the user types. To achieve this, we'll:
Here’s how you can implement the search functionality:
import React, { useState } from 'react';
import { Table, Input } from 'antd';
const { Search } = Input;
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
];
const dataSource = [
{ key: '1', name: 'Alice', age: 25, address: '123 Main St' },
{ key: '2', name: 'Bob', age: 30, address: '456 Park Ave' },
{ key: '3', name: 'Charlie', age: 35, address: '789 Elm St' },
{ key: '4', name: 'David', age: 40, address: '101 Oak St' },
];
function MyTable() {
const [searchText, setSearchText] = useState('');
const handleSearch = (value) => {
setSearchText(value);
};
const filteredData = dataSource.filter(record =>
record.name.toLowerCase().includes(searchText.toLowerCase()) ||
record.address.toLowerCase().includes(searchText.toLowerCase())
);
return (
<>
<Search
placeholder="Search..."
onSearch={handleSearch}
style={{ marginBottom: 16 }}
/>
<Table
columns={columns}
dataSource={filteredData}
pagination={false}
rowKey="key"
/>
</>
);
}
export default MyTable;
Explanation:
2. Highlighting Search Terms in Table Cells
Now, let’s highlight the search term in the table cells. We can achieve this by customizing the render function for each column. We’ll use React's dangerouslySetInnerHTML to insert highlighted text, and wrap the search term with a highlighted style.
Here’s how you can implement highlighting search terms within the table cells:
import React, { useState } from 'react';
import { Table, Input } from 'antd';
const { Search } = Input;
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name', render: (text) => highlightSearchTerm(text) },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address', render: (text) => highlightSearchTerm(text) },
];
const dataSource = [
{ key: '1', name: 'Alice', age: 25, address: '123 Main St' },
{ key: '2', name: 'Bob', age: 30, address: '456 Park Ave' },
{ key: '3', name: 'Charlie', age: 35, address: '789 Elm St' },
{ key: '4', name: 'David', age: 40, address: '101 Oak St' },
];
function MyTable() {
const [searchText, setSearchText] = useState('');
const handleSearch = (value) => {
setSearchText(value);
};
const filteredData = dataSource.filter(record =>
record.name.toLowerCase().includes(searchText.toLowerCase()) ||
record.address.toLowerCase().includes(searchText.toLowerCase())
);
const highlightSearchTerm = (text) => {
if (!searchText) return text; // No highlight if no search text
const regex = new RegExp(`(${searchText})`, 'gi');
const parts = text.split(regex);
return parts.map((part, index) =>
part.toLowerCase() === searchText.toLowerCase() ? (
<span key={index} style={{ backgroundColor: 'yellow' }}>{part}</span>
) : part
);
};
return (
<>
<Search
placeholder="Search..."
onSearch={handleSearch}
style={{ marginBottom: 16 }}
/>
<Table
columns={columns}
dataSource={filteredData}
pagination={false}
rowKey="key"
/>
</>
);
}
export default MyTable;
Explanation:
Result:
For a better user experience, use the loading prop to show a loading spinner while data is being fetched:
<Table loading={isLoading} columns={columns} dataSource={dataSource} />;
For errors, display a message to inform the user that data could not be fetched.
In this step, we will cover:
Let’s explore both approaches in detail.
1. Using Axios to Fetch Data
Axios is a popular JavaScript library for making HTTP requests. Here's how you can use Axios to fetch data for your Antd Table.
Example with Axios:
import React, { useEffect, useState } from 'react';
import { Table, Spin, Alert } from 'antd';
import axios from 'axios';
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
];
function MyTable() {
const [dataSource, setDataSource] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
axios
.get('https://api.example.com/data') // Replace with your API endpoint
.then((response) => {
setDataSource(response.data);
setLoading(false);
})
.catch((err) => {
setError('Error fetching data');
setLoading(false);
});
}, []); // Empty dependency array ensures it runs only once when component mounts
if (loading) return <Spin size="large" />; // Loading spinner
if (error) return <Alert message={error} type="error" />; // Error message
return <Table columns={columns} dataSource={dataSource} rowKey="key" />;
}
export default MyTable;
Explanation:
2. Using React Query for Data Fetching
React Query is a powerful data-fetching library that simplifies fetching, caching, synchronization, and state management of server data. It also comes with built-in error handling, retries, and caching features that make it perfect for modern web applications.
Example with React Query:
First, install React Query:
npm install react-query
Then, you can use React Query to fetch data:
import React from 'react';
import { Table } from 'antd';
import { useQuery } from 'react-query';
import axios from 'axios';
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
];
// Fetch function to be used with React Query
const fetchData = async () => {
const response = await axios.get('https://api.example.com/data'); // Replace with your API endpoint
return response.data;
};
function MyTable() {
const { data, isLoading, isError, error } = useQuery('fetchData', fetchData);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
return <Table columns={columns} dataSource={data} rowKey="key" />;
}
export default MyTable;
Explanation:
3. Combining Data Fetching with Antd Table
Both Axios and React Query can be integrated seamlessly with Antd Table. The main difference is in how they manage state, caching, and retries.
For example, with Axios, you manually handle the state (loading, dataSource, error), while React Query abstracts that away, providing cleaner and more maintainable code with automatic caching and refetching.
For both methods, error handling is crucial to provide a good user experience. You can display an error message or retry options when something goes wrong.
For React Query, you can configure it to retry requests on failure or add refetch intervals for real-time data:
const { data, isLoading, isError, error, refetch } = useQuery('fetchData', fetchData, {
retry: 3, // Retry up to 3 times if the request fails
refetchInterval: 5000, // Automatically refetch data every 5 seconds
});
if (isError) {
return (
<div>
Error: {error.message}
<button onClick={refetch}>Retry</button>
</div>
);
}
4. Handling Pagination with Backend Data
When integrating with backend APIs, you may need to implement server-side pagination. Here's an example of how to add pagination while fetching data with React Query:
const fetchDataWithPagination = async (page = 1, pageSize = 10) => {
const response = await axios.get('https://api.example.com/data', {
params: { page, pageSize }, // Send page number and size as query parameters
});
return response.data;
};
const { data, isLoading, isError, error } = useQuery(
['fetchData', page, pageSize], // Cache query based on pagination
() => fetchDataWithPagination(page, pageSize)
);
// Pass data into the Table with pagination
<Table
columns={columns}
dataSource={data?.items}
pagination={{
total: data?.total, // Total number of items from API
pageSize,
onChange: (page) => setPage(page),
}}
/>
Explanation:
Also read - React Functional Components with Examples [In-Depth Guide]
With the basic setup in place, let’s explore how you can customize the Antd Table to make it fit your specific needs and enhance its functionality.
Customizing the Antd Table component is where it really shines. It lets you create tables that are interactive, visually appealing, and perfectly suited to your app’s specific needs.
For example, use cases like user management dashboards or order processing tables often require features like inline editing or conditional formatting. Whether you're dealing with simple lists or complex data, fine-tuning your table can make the experience smoother and more intuitive for your users. Let’s take a look at some of the key ways you can customize the Antd Table to meet those needs.
The Antd Table customization begins with defining the columns. By specifying the data types of each column—whether it’s text, numbers, or dates—you ensure the data is displayed correctly. For example, formatting numbers with commas or dates with human-readable formats can enhance usability.
Here’s an example of formatting numbers and dates:
const columns = [
{
title: 'Amount',
dataIndex: 'amount',
key: 'amount',
align: 'right',
render: (text) => new Intl.NumberFormat().format(text), // Format numbers with commas
},
{
title: 'Date',
dataIndex: 'date',
key: 'date',
align: 'center',
render: (text) => new Date(text).toLocaleDateString(), // Format date
},
];
{
title: 'Amount',
dataIndex: 'amount',
key: 'amount',
align: 'right', // Align numbers to the right for cleaner readability
}
Additionally, column headers can be customized to reflect more descriptive titles. You can even add tooltips for extra context.
const columns = [
{
title: 'Action',
key: 'action',
align: 'right',
render: (_, record) => (
<button onClick={() => alert(`Editing ${record.name}`)}>Edit</button>
),
},
];
You can even add status indicators or icons based on the data.
{
title: 'Status',
dataIndex: 'status',
key: 'status',
align: 'center',
render: (status) => (
<span style={{ color: status === 'Active' ? 'green' : 'red' }}>
{status}
</span>
),
}
In this case, the Status column is dynamically rendered with different text colors depending on the value (Active or Inactive).
Antd Table excels at displaying dynamic data fetched from APIs or real-time sources, using JavaScript or Java on the backend. This is a core use case for any modern web app. Let's break down how to fetch and manage dynamic data for the table.
Here’s an example of fetching data and displaying it in your table:
import React, { useState, useEffect } from 'react';
import { Table } from 'antd';
const DynamicTable = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/users')
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch(() => setLoading(false)); // Handle errors
}, []); // Only run once when component mounts
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Email', dataIndex: 'email', key: 'email' },
{ title: 'Role', dataIndex: 'role', key: 'role' },
];
return <Table columns={columns} dataSource={data} loading={loading} rowKey="id" />;
};
export default DynamicTable;
Here’s how it works: whenever a user changes the page or adjusts a filter, the onChange function will trigger, allowing you to update the page, pageSize, or filters in your local state. This ensures the table’s content is always in sync with the user’s preferences. It’s a simple way to create a more interactive and responsive table without needing to refresh the entire page.
For instance, you could use the onChange prop like this:
const handleTableChange = (pagination, filters, sorter) => {
setPage(pagination.current);
setPageSize(pagination.pageSize);
setSortedInfo(sorter);
setFilteredInfo(filters);
};
<Table
columns={columns}
dataSource={data}
pagination={{ current: page, pageSize }}
onChange={handleTableChange}
/>
This keeps your table dynamic and responsive to user input, making it feel more interactive and fluid.
Also read - Top 28 React Projects for Beginners in 2025 [Source Code Included]
While customizing the table, you may run into challenges. Let’s take a look at common issues and best practices for troubleshooting them.
While the Antd Table is an incredibly powerful component, working with it, especially in real-world applications, comes with its own set of challenges. By recognizing these hurdles early on and following best practices, you can ensure your table performs smoothly, remains accessible, and looks great across all devices.
Let’s explore some common issues and explore effective ways to tackle them.
For large datasets, pagination and server-side processing are crucial. The Antd Table features like pagination make it easier to break down the data into smaller, more manageable chunks, allowing for smoother user interactions. Another useful feature is virtual scrolling, which enables you to display only the rows visible on the screen, greatly improving performance when working with vast amounts of data.
Best Practices:
<Table
columns={columns}
dataSource={data}
pagination={{ pageSize: 10 }}
/>
const fetchData = async (page, pageSize) => {
const response = await fetch(`api/data?page=${page}&pageSize=${pageSize}`);
return await response.json();
};
Example setup with react-virtualized:
import { Table } from 'antd';
import { List } from 'react-virtualized';
const VirtualizedTable = () => {
return (
<List
width={1000}
height={400}
rowCount={data.length}
rowHeight={50}
rowRenderer={({ index, key, style }) => (
<div key={key} style={style}>{data[index].name}</div>
)}
/>
);
};
Debounce input filters and search: To optimize performance when filtering or searching, you can use debouncing to limit the frequency of updates and API calls. This reduces unnecessary re-renders and improves the user experience.
You can achieve debouncing using lodash.debounce or React's useCallback with setTimeout. Here's a quick example with lodash.debounce:
import debounce from 'lodash.debounce';
const handleSearch = debounce((value) => {
setSearchText(value);
}, 300); // Adjust debounce time as needed
Alternatively, using useCallback with setTimeout:
const handleSearch = useCallback((event) => {
const timeoutId = setTimeout(() => {
setSearchText(event.target.value);
}, 300);
return () => clearTimeout(timeoutId); // Clear timeout if function is called again
}, []);
Both methods help in reducing the number of function calls during rapid user input.
Creating accessible tables ensures that all users, including those using screen readers or keyboard navigation, can interact with your data.
How to Improve Accessibility:
Tables often struggle on small screens because of their inherent width and complexity.
Tips for Making Antd Tables Mobile-Friendly:
Even with its strengths, developers often run into a few common issues when using Antd Table:
When you run into issues with Antd Table, following a structured debugging process can help you quickly identify and resolve the problem.
Here’s a step-by-step guide to troubleshooting common issues:
By following this flow, you can systematically troubleshoot Antd Table issues and get your table back on track quickly.
Also read - React JS Architecture Explained: Explore Step-by-Step Implementation and Key Tools
Learning React and components like the Antd Table can be challenging without the right guidance. With Ant Design Table customization, you can fine-tune the table to suit the unique needs of your application. From editable cells to fixed headers, Antd Table features provide the flexibility you need to build interactive and responsive tables for dynamic datasets.
A common challenge developers face is choosing the right resources to grow their skills and career. upGrad offers industry-aligned courses that bridge this gap, providing hands-on experience and deep dives into advanced topics like state management, API integration, and performance optimization.
In addition to the courses mentioned above, here are some free courses that can further strengthen your foundation in React and Java:
Are you unsure how to advance your React skills or navigate your career path? Schedule a free career counseling session with our experts for personalized guidance, or visit your nearest upGrad offline center for hands-on support.
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Reference:
https://www.softnoesis.com/blog/the-rise-of-react-js-development-services-in-india/
900 articles published
Director of Engineering @ upGrad. Motivated to leverage technology to solve problems. Seasoned leader for startups and fast moving orgs. Working on solving problems of scale and long term technology s...
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources