How to create a resizable table in React

Table resizable React

Let's start rendering a basic table in React:

jsx
import React from 'react';

const Table = () => {

    const data = [
        ['Erik',    '27.10.1990', 'Barcelona'],
        ['Andrea',  '16.10.1993', 'Barcelona'],
        ['Paula',   '06.03.2005', 'Barcelona']
    ];

    return(
        <table>
            <tbody>
                {data.map((row, i) => 
                    <tr key = {i}>
                        {row.map((col, j) => 
                            <td key = {j}>
                                {data[i][j]}
                            </td>
                        )}
                    </tr>
                )}
            </tbody>
        </table>
    );

}

export default Table;

Now, add an invisible element at the end of each cell and create 2 functions:

  • handleStart(): Saves the initial position of the mouse and the size of the cell.
  • handleMove(): Calculates the difference in pixels between the end and initial position of the mouse and resizes the element accordingly.

The invisible element will be placed behind the table border and will activate the previous functions depending on the user's behavior.

jsx
import React, { useState } from 'react';

const Table = () => {

    const [drag, setDrag] = useState(false);

    const data = [
        ['Erik',    '27.10.1990', 'Barcelona'],
        ['Andrea',  '16.10.1993', 'Barcelona'],
        ['Paula',   '06.03.2005', 'Barcelona']
    ];

    const handleStart = (e, row, col) => {

        let iniMouse = e.clientX;
        let iniSize  = document.getElementById(`${row}${col}`).offsetWidth;

        setDrag({
            iniMouse: iniMouse,
            iniSize:  iniSize
        })

    }

    const handleMove = (e, row, col) => {

        if(e.clientX){

            let iniMouse = drag.iniMouse;
            let iniSize  = drag.iniSize;
            let endMouse = e.clientX;

            let endSize = iniSize + (endMouse - iniMouse);

            document.getElementById(`${row}${col}`).style.width = `${endSize}px`;

        }

    }

    return(
        <table>
            <tbody>
                {data.map((row, i) => 
                    <tr key = {i}>
                        {row.map((col, j) => 
                            <td  key = {j} id = {`${i}${j}`}>
                                {data[i][j]}
                                <div 
                                    className   = 'Dragger'
                                    draggable   = {true}
                                    onDragStart = {(e) => handleStart(e, i, j)}
                                    onDrag      = {(e) => handleMove(e, i, j)}
                                />
                            </td>
                        )}
                    </tr>
                )}
            </tbody>
        </table>
    );

}

export default Table;

Here is the CSS:

CSS
table{
    border-collapse: collapse;
}
table td{
    border: 1px solid gray;
    position: relative;
}
.Dragger{
    cursor: col-resize;
    height: 100%;
    position: absolute;
    right: -4px;
    top: 0;
    width: 8px;
    z-index: 1;
}

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.