Data has become crucial for managing everything in our work life, positively impacting many people and companies. Visualization is key, and tabular form stands out for its ability to explain maximum details in minimal space. By dividing data into categories and presenting it in a row and column format, it simplifies understanding and increases user activity. This article focuses on creating Ant design tables in React, a powerful JS library. Ant design allows for creating stylish tables and other UI components. Start your journey with our React Certification Course. Let's begin...
What is Ant Design?
Ant Design is an open-source library for creating beautiful and elegant Ui components. It is created by Alibaba, a Chinese company, as a plethora of easy-to-use components for creating UI components very easily without writing much logic like we have to when we create something using hooks. company as a plethora of easy-to-use components for creating UI components very easily without writing much logic like we have to when we create something using hooks.
There is much more to Ant design than it meets the eye as it has provided us with complete design guidelines, best practices, design resources, and design tools to help designers quickly produce high-quality product prototypes.
How Tables Work in Ant Design ?
As previously told, Ant design has tons of pre-built components that make it easier to build a ant design table component with many different functionalities like sorting, filtering, searching, deleting, editing, multiple sorting, drag and drop, pagination, etc. to it.
All these functionalities have been provided to us in the form of props, and we are allowed to use them with dome js logic and hooks to make our app stylish
Some of the props are as follows
Table Props
Props | Explanation |
bordered:
| It is used to indicate whether to show all table borders or not. |
columns | Used to denote all the columns of the table |
dataSource | used to denote the data record array to be displayed. |
pagination | used for the configuration of the pagination |
scroll
| used to indicate whether the table can be scrollable or not |
sortDirection | used to denote the sort directions |
sticky | used to set a sticky header and scroll bar |
title | used to denote the table title renderer. |
Column Props
Props | Explanation |
align | used to specify which way that column is aligned. |
dataIndex | used to display the field of the data record |
defaultFilteredValue | used to denote the default filtered values |
defaultSortOrder | used to denote the default order of sorted values. |
editable | used to indicate whether a column can be edited |
filters | used to denote the filter menu config |
render | render the table cell |
sorter | sort function for local sort.. |
onCell | used to set props per cell. |
key | used to set a unique dataIndex |
onFilter | is a callback function that determines if the row is displayed when filtered. |
Most of the above-mentioned react props have been used in the table which we will be making in this blog, so feel free to review them whenever we are using a prop from the above table, and if any props besides the one mentioned above are being used in the table, it will be explained there itself.
Getting Started
We have used the following dummy employee data, which is in JSON format and stored in a separate file named Data.js, which will be called dynamically in our App component.
export const data = [
{
id: 1,
name: "Leanne Graham",
email: "Sincere@april.com",
address: "London Kulas Light Apt. 556",
phone: 1 - 7799 - 736 - 89931,
website: "https://tekolio.com/",
},
{
id: 2,
name: "Ervin Howell",
email: "Shanna@melissa.org",
address: "New York Victor Plains Suite 879" ,
phone: 99199 - 692 - 65935,
website: "anastasia.net",
},
{
id: 3,
name: "Clementine Bauch",
email: "Nathan@yesenia.net",
address: "Douglas Extension uitzipcod",
phone: 1 - 463 - 123 - 4447,
website: "ramiro.info",
},
{
id: 4,
name: "Patricia Lebsack",
email: "Julianne.OConner@kory.org",
address: "Hoeger Mal Apt. 692 South Elvis",
phone: 493 - 1799 - 9623,
website: "kale.biz",
},
{
id: 5,
name: "Chelsey Dietrich",
email: "Lucio_Hettinger@annie.com",
address: "Skiles ks Suit 51 Roscoevi",
phone: 254 - 954 - 1289,
website: "demarco.info",
},
{
id: 6,
name: "Mrs. Dennis Schulist",
email: "Karley_Dach@jasper.net",
address: "Norberto Crossing",
phone: 1 - 477 - 935 - 8478 - 64399,
website: "ola.org",
},
{
id: 7,
name: "Kurtis Weissnat",
email: "Telly.Hoeger@billy.com",
address: "Rex Tra Suite 2 Howemouth",
phone: 2199 - 9967 - 6132,
website: "elvis.io",
},
{
id: 8,
name: "Nicholas Runolfsdottir V",
email: "Sherwood@rosamond.net",
address: "Ellsworth mit Sui 729 Aliyavi",
phone: 493.6943 - 1499,
website: "jacynthe.com",
},
{
id: 9,
name: "Glenna Reichert",
email: "Chaim_McDermott@dana.org",
address: "Dayna Park uitzipcod",
phone: 976 - 6794 - 412996,
website: "conrad.com",
},
{
id: 10,
name: "Clementina DuBuque",
email: "Rey.Padberg@karina.com",
address: "Kattie Turnpike Suite 198 Lebsackbury",
phone: 9924 - 648 - 38994,
website: "ambrose.net",
}
We have only used vanilla CSS, and no other library has been used except for Ant Design for styling purposes. This project is all about creating a table in Ant design, thus, we will not be explaining any CSS code which we have written to style it.
How to Create our React Component
It's very easy to create a React App – just go to your working directory in any of your preferred IDEs and enter the following command in the terminal:
npx create-react-app react-table-using-antd
If you are unsure how to properly set up a create-react-app project, you can refer to the official guide here at create-react-app-dev.
After the setup, run npm start in the same terminal to start the localhost:3000 where our React app will be hosted. We can also see all our changes there.
Installing the Ant Design Library in our Project
Like any other library, it can also be installed in our project using either npm or yarn
$ npm install antd
$ yarn add antd
Other than npm and yarn, it also supports cnpm.
Working on the UI part of our Ant design table
Now that we have successfully set up our React project, it’s time to fetch our data from Data.js and use it in our UI.
For this, we will first need to import our data in our App.js component and then use the react useState hook for managing the state of our data.
import React from "react";
import { data } from "./Data";
import { Table } from "antd";
const App = () => {
const [Data, setData] = useState(data);
return (
<>
<div className="app">
<div className="table">
<Table dataSource={Data} columns={columns} pagination={false} />
</div>
</div>
</>
);
};
export default App;
In the above code, we have used the Table Component from the antd to display our data from the Data.js file in a tabular format, and for that, we need two props - dataSource and columns, from the list of table props listed above. Not only that, but the basic antd table is by default a pagination table, but we will explain it later in this blog, that’s why the pagination prop has been equated to false.
The dataSource prop is responsible for displaying the data, while the columns prop will be responsible for categorizing and dividing the data based on their title.
const columns = [
{
key: "name",
title: "Name",
dataIndex: "name",
},
{
key: "email",
title: "Email",
dataIndex: "email",
},
{
key: "address",
title: "Address",
dataIndex: "address",
},
{
key: "phone",
title: "Phone Number",
dataIndex: "phone",
},
{
key: "website",
title: "Website",
dataIndex: "website",
},
]
The props used above are already explained in the above table, so feel free to check them for more details.
Only the Table Component of the antd was required to create a table with the dataSource and the column we have explained above, and it will look like this
Adding & Deleting Functionalities
As the name suggests, with this, we can delete any row that we don't want anymore in the table. For this, we have to add a new column in the table called Actions. It will not only hold the delete button but the edit button as well, which will be responsible for the edit functionality, and for that, we will be using the icons provided to us by the antd, like DeleteOutLined, like a delete button
const columns = [
{
key: "name",
title: "Name",
dataIndex: "name",
},
{
key: "email",
title: "Email",
dataIndex: "email",
},
{
key: "address",
title: "Address",
dataIndex: "address",
},
{
key: "phone",
title: "Phone Number",
dataIndex: "phone",
},
{
key: "website",
title: "Website",
dataIndex: "website",
},
{
key: "action",
title: "Actions",
render: (record) => {
return (
<>
<DeleteOutlined
style={{ color: "red" }}
onClick={() => Delete(record)}
/>
</>
);
},
},
];
In the above code, we have again used some props like key, dataIndex, title, and render, which again have been explained above. The render prop is used to manipulate the data of the cell. Here it is used to delete the contents of all the cells of a specific row using the filter method as shown.
const Delete = (record) => {
setData((pre) => {
return pre.filter((person) => person.id != record.id);
});
};
Here the pre keyword contains all the data of that specific row that we want to delete, and by using the filter method, we can delete that row. Let's make it more realistic by adding a dialogue box that confirms our decision to delete the row as it will be permanent. We can do this simply by adding a modal using the Modal from antd as shown.
const Delete = (record) => {
Modal.confirm({
title: "Are you sure you want to delete this",
onOk: () => {
setData((pre) => {
return pre.filter((person) => person.id != record.id);b
});
},
});
};
Edit Functionality
Just like the delete functionality, it will also be triggered by an icon EditOutLined which is again one of the pre-built icons that antd has to offer, which will be responsible for triggering the edit functionality that we have provided this button by using the onClick Event Handler.
[
{
key: "action",
title: "Actions",
render: (record) => {
return (
<>
<div className="flex">
<EditOutlined
style={{ color: "black" }}
onClick={() => Edit(record)}
/>
<DeleteOutlined
style={{ color: "red" }}
onClick={() => Delete(record)}
/>
</div>
</>
);
},
},
];
Here we will again be using the Modal Component from antd but to display the original values in the order in which they have been shown in the table for editing purposes as well, and for that, we need a state to manage its visibility which will be triggered with the edit functionality.
const [visible, setVisible] = useState(false);
const Edit = () => {
setVisible(true);
};
<Modal
title="Edit Details"
visible={visible}
onCancel={() => setVisible(false)}
onOk={() => setVisible(false)}
okText="Save"
></Modal>;
Initially, the value of this state is false, meaning the Modal will not be visible until we click the edit button, which will trigger the setVisible function making the value of the visible state true.
We will be seeing an empty Modal with the title we have given it and the two buttons which says 'save' and 'cancel' as shown.
It is time to fill this empty Modal with the data of the respective row which the user wants to Edit, and for that, we need another state in which we will be storing the original values and displaying them in the Modal, and updating them in the table in its respective position as well.
const [edit, setEdit] = useState(null);
Now let's make some input fields in the Modal itself so that we can view the data of the row and then edit it there itself.
<Input
value={edit?.name}
onChange={(e) => {
setEdit((pre) => {
return { ...pre, name: e.target.value };
});
}}
/>
<Input
value={edit?.email}
onChange={(e) => {
setEdit((pre) => {
return { ...pre, email: e.target.value };
});
}}
/>
<Input
value={edit?.address}
onChange={(e) => {
setEdit((pre) => {
return { ...pre, address: e.target.value };
});
}}
/>
<Input
value={edit?.phone}
onChange={(e) => {
setEdit((pre) => {
return { ...pre, phone: e.target.value };
});
}}
/>
<Input
value={edit?.website}
onChange={(e) => {
setEdit((pre) => {
return { ...pre, website: e.target.value };
});
}}
/>
As told above, we have used the Input fields from antd to display all the values of the respective row using the value attribute and the edit state, which at this point contains all the values of that row, but this will only display the values, we can’t edit them.
For that, we have added the onChange event handler, which will trigger the setEdit function enabling the edit functionality so that we can edit the values and update the row with the new values by clicking the save button.
<Modal
title="Edit Details"
visible={visible}
okText="Save"
onCancel={() => /*setVisible(false)*/ ResetEditing()}
onOk={() => /*setVisible(false)*/ {
setData((pre) => {
return pre.map((student) => {
if (student.id === edit.id) {
return edit;
} else {
return student;
}
});
});
ResetEditing();
}}
></Modal>;
If you are new to the world of React and want to make awesome tables and apps like this, take our web development complete course and get started on the path of becoming a front-end developer.
Adding Pagination
As told already, the antd table is by default a pagination table, and removing the pagination prop, which was turned off from the Table component, will bring our pagination back and display it at the bottom right corner.
<Table dataSource={Data} columns={columns} />;
But this position of the pagination information can be placed anywhere like 'topLeft', 'topCenter', 'topRight', 'bottomLeft', 'bottomCenter', and/or 'bottomRight'. If you want to change the position to any of the mentioned places, just change the pagination code to any of the following
<Table
pagination={{ position: ["topLeft"] }}
pagination={{ position: ["bottomLeft"] }}
pagination={{ position: ["topCenter"] }}
pagination={{ position: ["bottomCenter"] }}
pagination={{ position: ["topRight"] }}
pagination={{ position: ["bottomRight"] }}
/>;
A page’s default size is 10 rows, but we change it either from the code itself or allow the user to change it from the table. The prop pageSize is used to change the size of the page from the code.
But if we want the user to change the size of the page according to his own will, use the showSizeChanger prop, which will give the user a select component with different page size values for him to select.
<Table
dataSource={Data}
columns={columns}
pagination={{ pageSize: 8, total: 50, showSizeChanger: true }}
/>;
Sorting functionality
Adding the sorting functionality in the table is very easy. We just have to use the sorter prop one of the column props provided to us by the Antd, which when used in any column gives us the ability to sort the data of that column alphanumerically.
{
key: "name",
title: "Name",
dataIndex: "name",
sorter: (a, b) => a.name > b.name,
sortDirections: ["descend"],
}
This sorter prop does nothing special, just follows the same rules of the Compare Function of sorting in JavaScript which we are all familiar with - just look at the syntax.
In the above code, we are sorting the rows based on the alphabetical order of their names which by default will be based on their first name. If we want it to perform based on the last name we have to specify the conditions accordingly.
The other prop we have used here is the sortDirections that have already been explained in the above table of table props. We have given the value “descend” which means sort the table in descending order and is denoted by the carrot symbol we have used while denoting the dropdown menus in many apps or websites.
The default value of sortDirections is ['ascend', 'descend'] which means on the first click, the column header sorts rows in ascending order while the second click sorts rows in descending order, and the third click removes the sort, and then the cycle repeats.
Adding ['ascend'] at the end will never remove the sort from the table as now in the Third click will sort the rows again in ascending order followed by descending order in a never-ending cycle.
The official documentation states, “Use sorter to make a column sortable. sorter can be a function of the type function(a, b) { ... } for sorting data locally.
sortDirections: ['ascend' | 'descend'] defines available sort methods for each column, effective for all columns when set on table props. You can set as ['ascend', 'descend', 'ascend'] to prevent sorter back to default status.”
Filter functionality
Just like the sorting functionality, this can also be added simply using props from column props - filters. This prop is used to generate the filter menu in the column itself and by using another prop from the column props - onFilter, we can add the functionality on the menu we have made using the filters prop.
[
{
key: "address",
title: "Address",
dataIndex: "address",
filters: [
{
text: "London",
value: "London",
},
{
text: "New York",
value: "New York",
},
],
onFilter: (value, record) => record.address.indexOf(value) === 0,
},
];
The above code filters the address of the employees, but there is a catch. Here the address starts with the name of the city like London and New York and the code has been written keeping that in mind only.
There can be many items on this menu made by using the filters prop and we can even make a sub-menu from the menu itself like the name of the street in London can work as a new menu for filtering rows.
Here is the final output -
output
Unlock Your Potential with Python: Get Certified in the Most Dynamic Programming Language Today!
Implementing Search and Highlighting in the Ant design Table
Implementing the searching mechanism:
- Use the onSearch event handler to update the search input value and filter the data based on it.
- Render a search input component and link it to the search function.
- Display the filtered rows in the table using the state variable for filtered data.
Implementing the highlighting mechanism:
- Create a function that takes search input text and returns the output in the form of highlighted text.
- Use the customRender property to apply the highlighting function to the cell data.
- Finally, render the table component in your application.
// Function to handle search input changes
const handleSearch = (value) => { // 2
setSearchInput(value); // 2
// Filter data based on the search input.
const filtered = data.filter((item) => // 2
Object.values(item).some(
(val) => val && val.toString().toLowerCase().includes(value.toLowerCase())
)
);
setFilteredData(filtered); // 2
};
// Function to highlight search matches in cell data
const highlightSearch = (search, cellData) => { // 3
const regex = new RegExp((${search}), 'gi'); // 3
return cellData.toString().replace(regex, (match) => <span class="highlight">${match}</span>); // 3
};
Adding Loading and Error States to the AntD Table
- Start by setting the initial loading state to 'true' and the error state to 'false'.
- Fetch data from the data using the asynchronous function or API call.
- Now, while fetching data, keep track of the loading state to make changes wherever required.
- Suppose an error occurs in this stage, then update the error state to 'true'.
- Now render the table component with its loading properties.
- While rendering, handle the error states side by side.
- Use the spin component to customize the loading state appearance.
- Finally, render the table component in your application.
useEffect(() => {
const fetchData = async () => {
try {
// Simulate an API call or asynchronous function to fetch data
const response = await fetch('https://api.example.com/data');
const result = await response.json();
// Update loading state to false after data is fetched
setLoading(false);
setData(result);
} catch (error) {
// If an error occurs during fetching, set error state to true
setLoading(false);
setError(true);
}
};
// Call the function to fetch data when the component mounts
fetchData(); }, []);
Integrating AntD tables with backend APIs
- Use the 'useEffect' method to fetch data from the backend (by making an API request).
- Now update the state variable within that API request.
- Render the table component with the data obtained from the API.
- Now customize the columns based on the data received from the backend API.
- Handle error states while fetching data from the API.
- Apply pagination, filtering, and sorting properties to customize the appearance of the AntD properties.
- Implement functions or callbacks to manage user actions on the table, like editing or deleting data.
- Now, based on further user actions, make API requests to update the overall backend data.
useEffect(() => {
const fetchData = async () => {
try {
// Make an API request to fetch data
const response = await axios.get('https://api.example.com/data');
const result = response.data;
// Update state with the fetched data
setData(result);
setLoading(false); // Update loading state
} catch (error) {
// Handle errors
setError(true);
setLoading(false);
message.error('Error fetching data from the API');
}
};
Best Practices and Tips for Working with the AntD Table
1. Setting up nvm to manage different versions of npm: It is often seen that some npm versions may not be compatible with particular devices or applications. So, to tackle this issue, you can use:
- nvm use (to switch between versions).
- nvm install version-name (to install a particular version).
- nvm-install-latest-npm (to install the latest version of npm).
2. Assign unique identifiers to columns for better performance and to prevent rendering problems.
3. Fetch data in chunks and only the most important ones. This speeds up loading times.
4. Improve rendering efficiency by using techniques like React.memo or useMemo, especially for custom components within table cells.
5. Enhance the table performance by using virtual scrolling or lazy loading. This brings a significant change in improving the user experience.
6. Use built-in features like selecting rows and actions to handle bulk operations more efficiently.
Conclusion
In this blog, we have discussed how to make a table using antd with multiple functionalities like deleting, editing, sorting, pagination and filtering, but we can add as many features and functions in our table as we want from the vast variety of props available in antd like sticky columns or rows, infinite scrolling, drag and drop, etc.
This article only covers the introductory part of how to make a table in React using Ant design and the features and functions covered in this blog are very common features that should be present in a basic data table so that the user can have some kind of interaction with the table.
Now the question comes is, which library is better when it comes to making and designing a table in React. As I have told in the introductory part, there are many ways and libraries which give us the ability and built-in components and props to make a table with all the functionalities and we can also give it a proper design.
If you are having trouble keeping up or have some doubts about where to start learning React JS, check out the React Certification Course at KnowledgeHut and get started in your React Journey.
Check out What is StrictMode in React? blog posts for more information