editable text field in table using reactjs

Create an Editable Text Field in a Table Using ReactJS [Learn the Trick]

Author Profile
Abdul Basit OnLinkedIn

Today, we will explore how to build an editable table in React.js; a crucial topic for React developers.

In the ReactJS section of Codevertiser, we have already covered some essential React topics, such as handling forms, creating a quiz app, and many others.

Demo App

This is a Demo App of what we are about to learn and build in this article, you can play with it.

Table with Editable Text Field
NameEmailPosition


Editable text fields in a table enhance the user experience of a React App. It might seem difficult to build, but it becomes easy with the right tricks. There are many ways to create them, but I’ll share the easiest one, so you can do it without getting exhausted. Let's get started.

Codepen Demo | Editable Table

If you are only interested in code, you can find it below on the Codepen widget. However, if you want to learn how to build it step by step, follow the article.

Creating the Editable Text field in Table

Step 01: Create Table

In the first step, create a simple table like we do with plain HTML5. A simple table is created to make the base for the editable text fields. After building the table, we will turn the Table Data: td into an editable text.

function EditableTable() {
return (
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Position</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>Frontend Developer</td>
</tr>
<tr>
<td>Sara</td>
<td>HR Executive</td>
</tr>
<tr>
<td>Mike</td>
<td>Backend Developer Developer</td>
</tr>
</tbody>
</table>
</div>
)
}
export default EditableTable

Now we have to figure out how to turn this td: table data into editable field.

The first thing that came into mind is to wrap input inside td.

Let’s make the code clean

Before moving to Editable Text Field let’s make this component a bit cleaner.

In real-world apps, we get data via APIs. So to mock it, we will build an array of objects.

import { useState } from 'react'
const data = [
{
id: '01',
name: 'John Doe',
position: 'Frontend Developer',
},
{
id: '02',
name: 'Sara',
position: 'HR Executive',
},
{
id: '03',
name: 'Mike',
position: 'Backend Developer',
},
]
const EditableTable = () => {
const [employeeData, setEmployeeData] = useState(data)
return (
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Position</th>
</tr>
</thead>
<tbody>
{employeeData.map(({ id, name, email, position }) => (
<tr key={id}>
<td>{name}</td>
<td>{email}</td>
<td>{position}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
export default EditableTable

Step 02: Editable Table Data

The primary option that comes to mind for making editable table data is wrapping the td tag into the input tag. Let us do this first.

<tbody>
{employeeData.map(({ employeeId, name, email, position }) => (
<tr key={employeeId}>
<td>
<input
name="name"
value={name}
type="text"
onChange={onChangeInput}
placeholder="Type Name"
/>
</td>
<td>
<input
name="email"
value={email}
type="text"
onChange={onChangeInput}
placeholder="Type Email"
/>
</td>
<td>
<input
name="position"
type="text"
value={position}
onChange={onChangeInput}
placeholder="Type Position"
/>
</td>
</tr>
))}
</tbody>

But here is one problem…

Now observe that the editable text field is not yet functional. In the next step, we will make it functional.

Step 03: Changing Table data Value

We have to write an onChange Handler Function for changing the table data value. This function is to handle the Input tag.

import { useState } from 'react'
import './index.css'
const data = [
{
employeeId: '01',
name: 'John Doe',
position: 'Frontend Developer',
},
{
employeeId: '02',
name: 'Sara',
position: 'HR Executive',
},
{
employeeId: '03',
name: 'Mike',
position: 'Backend Developer',
},
]
const EditableTable = () => {
const [employeeData, setEmployeeData] = useState(data)
const onChangeInput = (e, employeeId) => {
const { name, value } = e.target
console.log('name', name)
console.log('value', value)
console.log('employeeId', employeeId)
const editData = employeeData.map((item) =>
item.employeeId === employeeId && name ? { ...item, [name]: value } : item
)
console.log('editData', editData)
setEmployeeData(editData)
}
return (
<div className="container">
<h1 className="title">ReactJS Editable Table</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Position</th>
</tr>
</thead>
<tbody>
{employeeData.map(({ employeeId, name, email, position }) => (
<tr key={employeeId}>
<td>
<input
name="name"
value={name}
type="text"
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Name"
/>
</td>
<td>
<input
name="email"
value={email}
type="text"
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Email"
/>
</td>
<td>
<input
name="position"
type="text"
value={position}
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Position"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
export default EditableTable

Now the main part,

const onChangeInput = (e, employeeId) => {
const { name, value } = e.target
console.log('name', name)
console.log('value', value)
console.log('employeeId', employeeId)
const editData = employeeData.map((item) =>
item.employeeId === employeeId && name ? { ...item, [name]: value } : item
)
console.log('editData', editData)
setEmployeeData(editData)
}

You can see we have multiple consoles in this function, to debug that are we getting correct values.

Then we map over employeeData and check if the current employeeId equals to the id, and name also matches with name of input, we will change only that input values, the rest of the values will be the same.

To complete, we will setState and pass editData to it.

Read More On This

The article "Reusable Input Component in React" will help you understand how to build an input component in React with TypeScrip.

For insights on effectively updating objects within an array, refer to the article "How to Update an Array of Objects".

These resources will help you deepen your understanding of this topic.

Congrats, you have created the table with editable text fields.

What about making it stylish and interactive?

Styling the Editable Text fields in the Table

For interactivity, I added the hover effect, on a text field, so user can know he can interact with it.

We also removed the default border and styled input focus state, to make the user experience smooth.

Complete Code

import { useState } from 'react'
import './index.css'
const data = [
{
employeeId: '01',
name: 'John Doe',
position: 'Frontend Developer',
},
{
employeeId: '02',
name: 'Sara',
position: 'HR Executive',
},
{
employeeId: '03',
name: 'Mike',
position: 'Backend Developer',
},
]
const EditableTable = () => {
const [employeeData, setEmployeeData] = useState(data)
const onChangeInput = (e, employeeId) => {
const { name, value } = e.target
const editData = employeeData.map((item) =>
item.employeeId === employeeId && name ? { ...item, [name]: value } : item
)
setEmployeeData(editData)
}
return (
<div className="container">
<h1 className="title">ReactJS Editable Table</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Position</th>
</tr>
</thead>
<tbody>
{employeeData.map(({ employeeId, name, email, position }) => (
<tr key={employeeId}>
<td>
<input
name="name"
value={name}
type="text"
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Name"
/>
</td>
<td>
<input
name="email"
value={email}
type="text"
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Email"
/>
</td>
<td>
<input
name="position"
type="text"
value={position}
onChange={(e) => onChangeInput(e, employeeId)}
placeholder="Type Position"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
export default EditableTable

CSS

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;600&display=swap');
body {
box-sizing: border-box;
color: #220f5f;
font-family: 'Poppins', sans-serif;
}
.container {
width: 100%;
max-width: 800px;
padding: 0 10px;
margin: 0 auto;
margin-top: 70px;
}
.title {
text-align: center;
font-size: 26px;
margin-bottom: 30px;
}
table {
border-collapse: collapse;
width: 100%;
}
tr th {
font-size: 18px;
padding: 12px;
border: 1px solid #eeeeee;
text-align: left;
background-color: rgba(217, 221, 146, 0.2);
}
tr td {
border: 1px solid #eeeeee;
text-align: left;
}
input {
font-size: 16px;
background-color: transparent;
border: none;
width: 91%;
padding: 12px 12px;
font-family: 'Poppins', sans-serif;
}
input:hover {
background-color: #fffaf3;
}
input:focus {
outline: 1px solid #ccc;
border: 1px solid #ccc;
}

I hope you find this article valuable.