Languages
[Edit]
EN

React - create editable table

9 points
Created by:
Adnaan-Robin
274

In this short article we would like to show how to create simple editable table in React

Simple editable table in React.
Simple editable table in React.

Note: react this article to see standalone editable table cell example.

Practical example:

// ONLINE-RUNNER:browser;

//Note: Uncomment import lines during working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';

// CELL -----------------------------------------

const itemStyle = {
  	padding: '2px',
	border: '1px solid silver',
  	fontFamily: 'Arial',
  	fontSize: '13px',
  	display: 'flex'
};

const textStyle = {
  	...itemStyle,
  	padding: '5px 4px',
  	height: '16px'
};

const inputStyle = {
  	padding: '0',
	flex: '1',
    width: '100%',
  	minWidth: '20px',
  	fontFamily: 'Arial',
  	fontSize: '13px'
};

const buttonStyle = {
  	flex: 'none'
};

const Cell = React.memo(({value, mode, onChange}) => {
  	const [localMode, setLocalMode] = React.useState(mode ?? 'read');
  	const [localValue, setLocalValue] = React.useState(value ?? '');
  	React.useEffect(() => setLocalMode(mode ?? 'read'), [mode]);
  	React.useEffect(() => setLocalValue(value ?? ''), [value]);
	if (localMode === 'edit') {
        const handleInputChange = (e) => setLocalValue(e.target.value);
        const handleSaveClick = () => {
            setLocalMode('read');
          	onChange?.(localValue);
        };
        return (
          <div style={itemStyle}>
            <input type="text"
              value={localValue}
              style={inputStyle}
              onChange={handleInputChange} />
            <button style={buttonStyle} onClick={handleSaveClick}>Ok</button>
          </div>
        );
    }
  	if (localMode === 'read') {
        const handleEditClick = () => {
            setLocalMode('edit');
        };
        return (
          <div style={textStyle} onClick={handleEditClick}>{localValue}</div>
        );
    }
  	return null;
});

// ROW ------------------------------------------

const tdStyle = {
  	padding: '1px',
  	border: '1px solid black',
};

const optionStyle = {
  	...tdStyle,
  	width: '30px'
};

const Row = React.memo(({ mode, columns, data, onChange, onDelete}) => {
	const handleDeleteClick = () => onDelete?.();
    return (
      <tr>
        {columns.map(({path}, columnIndex) => {
            const handleChange = value => {
                if (onChange) {
                    const changedData = { ...data, [path]: value };
                    onChange(columnIndex, changedData);
                }
            };
            return (
              <td key={path} style={tdStyle}>
                <Cell 
                  mode={mode}
                  value={data[path]} 
                  onChange={handleChange} 
                />
              </td>
            );
        })}
        <td style={optionStyle}>
          <button onClick={handleDeleteClick}>Delete</button>
        </td>
      </tr>
    );
});

// TABLE ----------------------------------------

const tableStyle = {
    border: '1px solid black',
    borderCollapse: 'collapse',
  	width: '100%'
}

const Table = React.memo(({id, columns, data, onAdd, onChange, onDelete}) => {
    const [addedIndex, setAddedIndex] = React.useState();
  	const handleAddClick = () => {
    	onAdd?.(data.length);
      	setAddedIndex(data.length);
    };
	return (
      <div>
        <table style={tableStyle}>
          <tbody>
            <tr>
              {columns.map(({path, name}) => (
                <th key={path} style={tdStyle}>{name}</th>
              ))}
            </tr>
            {data.map((rowData, rowIndex) => {
            	const handleChange = (columnIndex, changedData) => {
                    onChange?.(rowIndex, columnIndex, changedData);
                };
              	const handleDelete = () => {
                  	if (rowIndex !== addedIndex) {
                  		setAddedIndex(addedIndex - 1);
                    }
                	onDelete?.(rowIndex, rowData);
                };
              	return (
                    <Row 
                      key={rowData[id]}
                      mode={addedIndex === rowIndex ? 'edit' : 'read'}
                      columns={columns}
                      data={rowData}
                      onChange={handleChange}
                      onDelete={handleDelete}
                    />
                );
            })}
          </tbody>
        </table>
        <br />
        <div>
          <button onClick={handleAddClick}>Add row</button>
        </div>
      </div>
    );
});

// Example --------------------------------------

const columns = [
  	{ path: 'id',   name: 'ID'   },
    { path: 'name', name: 'Name' },
    { path: 'age',  name: 'Age'  }
];

let counter = 0;

const App = () => {
  	const [data, setData] = React.useState(() => ([
        { id: ++counter, name: 'Bob',  age: 22 },
        { id: ++counter, name: 'Adam', age: 43 },
        { id: ++counter, name: 'Mark', age: 16 },
        { id: ++counter, name: 'John', age: 29 }
	]));
  	const handleAdd = (rowIndex) => {
      	const newRowData =  { id: ++counter };
    	setData([ ...data, newRowData ]);
      	//TODO: AJAX trequest to server
      	console.log(`Added empty row!`);
    };
  	const handleChange = (rowIndex, columnIndex, changedRowData) => {
      	const columnData = columns[columnIndex];
    	const changedRowJson = JSON.stringify(changedRowData, null, 4);
      	//TODO: AJAX trequest to server
      	console.log(`Changed row:\n${changedRowJson}`);
    };
  	const handleDelete = (rowIndex, removedRowData) => {
    	setData(data.filter((value, index) => index !== rowIndex));
      	//TODO: AJAX trequest to server
      	console.log(`Removed row: ${rowIndex}`);
    };
    return (
      <div>
        <Table
          id="id"
          columns={columns}
          data={data}
          onAdd={handleAdd}
          onChange={handleChange}
          onDelete={handleDelete}
        />
      </div >
    );
};

const root = document.querySelector('#root');
ReactDOM.render(<App/>, root );

ReactJS

React - editable table
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join