How To Create An Editable Text Field In Table Using ReactJS

6 min read

In this article, we are going to learn “how to build an editable table in Reactjs".

This is the result you can play with.

Table with Editable Text Field
NameEmailPosition


Many web apps nowadays are implementing tables with editable text fields. It enhances the user experience. Building editable text fields might seem arduous, but it becomes easy with the tricks. There are many ways to create them, but I’ll share the easiest one so you can do it without getting exhausted. So, let us get started.

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.

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;
}

Codepen Demo | Editable Table