Let's assume that you want to highlight the cells of a table using React. The starting point is to create the component and to render a table:
jsximport React from 'react'; const SuperTable = () => { const data = [ ['Erik', 30, 'Barcelona'], ['Andrea', 27, 'Barcelona'], ['Paula', 16, 'Calella'] ] return( <table> <tbody> { data.map((row, i) => <tr>{row.map((elem, j) => <td>{elem}</td>)} </tr> )} </tbody> </table> ); } export default SuperTable;
The previous example will display a normal table, nothing special here. Now it's time to add the sauce. 🥫
Use an array to save the start and the end position of the selection.
The array can be: [iniRow, iniCol, endRow, endCol]
.
Define a variable to check if the user is dragging the table. Finally, define 3 handlers to implement the desired actions on dragging.
jsximport React, { useState } from 'react'; const SuperTable = () => { const data = [ ['Erik', 30, 'Barcelona'], ['Andrea', 27, 'Barcelona'], ['Paula', 16, 'Calella'] ] // This array defines [iniRow, iniCol, endRow, endCol] const [select, setSelect] = useState([0, 0, 0, 0]); // This variable will control if the user is dragging or not const [drag, setDrag] = useState(false); const handleMouseDown = (e, row, col) => { // User starts to drag here } const handleMouseUp = (e, row, col) => { // User stops selecting and leaves the mouse } const handleMultipleSel = (e, row, col) => { // User is moving the mouse here } return( <table> <tbody> { data.map((row, i) => <tr>{row.map((elem, j) => <td onMouseDown = {(e) => handleMouseDown(e, i, j)} onMouseUp = {(e) => handleMouseUp(e, i, j)} onMouseMove = {(e) => handleMultipleSel(e, i, j)} className = {getClassName(i, j)} >{elem}</td>)} </tr> )} </tbody> </table> ); } export default SuperTable;
When the users click on a cell, the following function will execute (notice how you add the same cell as starting and ending point):
jsxconst handleMouseDown = (e, row, col) => { setDrag(true); setSelect([row, col, row, col]); }
When the user stops dragging, update the state:
jsxconst handleMouseUp = (e, row, col) => { setDrag(false); }
While the user is dragging, update the starting and ending point. Notice that depending on the user dragging direction, you'll modify the selection order.
Again, the goal is to always have an array like this one:
[iniRow, iniCol, endRow, endCol]
The ending position is greater than the starting position.
jsxconst handleMultipleSel = (e, row, col) => { e.preventDefault(); if(drag){ let [iniRow, iniCol, endRow, endCol] = select; if(iniRow <= row && iniCol <= col) setSelect([iniRow, iniCol, row, col]); if(iniRow >= row && iniCol >= col) setSelect([row, col, endRow, endCol]); } }
If a cell on the table is in between the interval defined by the select
array, set its className = 'Selected'
.
jsxconst getClassName = (row, col) => { let [iniRow, iniCol, endRow, endCol] = select; if(row >= iniRow && row <= endRow && col >= iniCol && col <= endCol){ return 'Selected'; } }
Finally, add some CSS to highlight selected cells.
css.Selected{ background: blue; user-select: none; }
Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.