How can I hover over multiple cells in a table?

Is there a way to change the color of multiple adjacent cells when hovering over one cell, and can this be done dynamically (so the number of adjacent cells that change color can vary)?

Here is the code snippet:

I'm using React to create a table with the following code:

<TableBody>
<TableRow>{tableRowGen()}</TableRow>
</TableBody>

The tableRowGen function looks like this:

const tableRowGen = () => {
    let cells = [];

    for (var i = 0; i < columnNumber; i++) {
      cells.push(
        <TableCell
          className={classes.td}
          onMouseEnter={() => {
            console.log("hi!");
          }}
          align="center"
        >
          {i}
        </TableCell>
      );
    }
    console.log(cells);
    return cells;
  };

Currently, I have a style for table cell hover effect (td) which turns the background red:

td: {
    ...
    "&:hover": {
      background: "#f00",
    },
  },

Example shown below:

This is how it currently looks:

https://i.stack.imgur.com/7ygFA.png

But is it possible to make cells 4 and 5 turn red when hovering only over 3? (as seen below)

https://i.stack.imgur.com/GHSID.png

EDIT: Updated tableRowGen function code:

const tableRowGen = () => {
    let cells = [];

    for (var i = 0; i < columnNumber; i++) {
      cells.push(
        <TableCell
          // className={classes.td}
          align="center"
          onMouseEnter={() => onMouseEnter(i)}
          onMouseLeave={onMouseLeave}
          className={Math.abs(hoveredCell - i) <= 14 ? classes.td : ""}
        >
          {i}
        </TableCell>
      );
    }
    return cells;
  };

Additional code based on suggestions:

const [hoveredCell, setHoveredCell] = React.useState(null);

  const onMouseEnter = React.useCallback((index) => {
    setHoveredCell(index);
  }, []);

  const onMouseLeave = React.useCallback(() => {
    setHoveredCell(null);
  }, []);

Answer №1

Here's a different approach to achieve this task.

To handle the hover event for each TableRow, consider creating a separate component specifically for that purpose.

const useStyles = makeStyles({
  highlighted: {
    background: "#f00"
  }
});

const MyTableRow = () => {
  const classes = useStyles();
  const columnNumber = 10;

  // specify the index of the cell that triggers highlighting on hover
  const targetIndex = 3;

  // define indices to be highlighted
  const indicesToHighlight = [3, 4, 5, 7, 9];

  // toggle state for highlighting
  const [highlight, setHighlight] = React.useState(false);

  function onMouseEnter(event) {
    setHighlight(parseInt(event.target.dataset.index) === targetIndex);
  }

  function onMouseLeave() {
    setHighlight(false);
  }

  const cells = [...Array(columnNumber)].map((_, i) => {
    const shouldHighlighted = indicesToHighlight.includes(i);
    const className = highlight && shouldHighlighted && classes.highlighted;

    return (
      <TableCell key={i} data-index={i} align="center" className={className}>
        {i}
      </TableCell>
    );
  });

  return (
    <TableRow onMouseMove={onMouseEnter} onMouseLeave={onMouseLeave}>
      {cells}
    </TableRow>
  );
};

https://codesandbox.io/s/suspicious-thompson-oovo6?fontsize=14&hidenavigation=1&theme=dark


Instead of using onMouseEnter, I opted for onMouseMove which triggers repeatedly as the mouse moves over the row compared to firing just once with onMouseEnter.

In order to avoid attaching an event listener to each individual cell, I decided to implement event delegation technique where only one element handles the event.

Answer №2

If you're looking to achieve this effect using javascript, you can easily add or remove css classes when the user hovers over an element. Alternatively, you can also accomplish this with pure css by utilizing a sibling selector. Here's a straightforward example:

td:hover {
  background-color: red;
}

td:hover + td {
  background-color: red;
}

td:hover + td + td {
  background-color: red;
}
<table>
  <tbody>
    <tr>
      <td>1,1</td>
      <td>1,2</td>
      <td>1,3</td>
      <td>1,4</td>
    </tr>
    <tr>
      <td>2,1</td>
      <td>2,2</td>
      <td>2,3</td>
      <td>2,4</td>
    </tr>
  </tbody>
<table>

This code snippet shows a static version of the effect - for a dynamic approach where the number of cells varies, incorporating javascript will be necessary.

Answer №3

When using CSS, you can only highlight cells next to the one being hovered over:

td:hover, td:hover + td {
  background-color: red;
}

However, if you want to highlight cells based on certain conditions, you may need to use JavaScript. This involves detecting hover events and determining which cells should be highlighted based on the hoveredCell. For example, if you only want to highlight directly adjacent cells, you can add a class to the cell that meets the condition:

const [hoveredCell, setHoveredCell] = useState<number | null>(null);

const onMouseEnter = React.useCallback((index) => {
    setHoveredCell(index);
}, []);

const onMouseLeave = React.useCallback(() => {
    setHoveredCell(null);
}, []);

<TableCell
  onMouseEnter={() => onMouseEnter(index)}
  onMouseLeave={onMouseLeave}
  className={Math.abs(hoveredCell - index) <= 1 ? classes.hovered : ''}
>

The condition

Math.abs(hoveredCell - index) <= 1
can be turned into a function that takes in hoveredCell and index as arguments, allowing for customization via props. Alternatively, you can simply adjust the number in the condition to target a different number of cells.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What specific data am I sending from my ajax request to the MVC controller?

How can I determine the appropriate parameter to use when passing a JavaScript object? Please see below: var all = []; //iterate through each instrument for (var i = 0; i < 3; i++) { var txt = getThis(i);//int var detail =getThat(i);//string ...

Having trouble locating module '@mdx-js/mdx' in Gatsby forest

Since the most recent update today, I've been encountering this error. There is no MDX being used in my project at all.. When running npm run develop, this issue arises. Does anyone have any insights on this? internal/modules/cjs/loader.js:979 thro ...

When an image is loaded, use Jquery to automatically open a new tab, instead of

I need to implement a function where, on loading an image on a page, a new tab opens and starts downloading a file from a specific URL while keeping the original page open. This task is part of a WordPress site with a jQuery section in the backend. I' ...

Guide to retrieve the file name into a text box upon selection (Avoid displaying as c:/fake path/)

I am trying to achieve the functionality where after choosing a file in a file input, the file name is automatically displayed in a text box named file_name without needing to click or submit any button. Unfortunately, I have been unable to find the correc ...

Is the RadioButton change jQuery function malfunctioning following modifications to the DOM?

After updating the HTML of the radio button (with the same name) through AJAX based on certain logic (such as rate or duration changes), I noticed that the change(function(e) method worked perfectly before the DOM was updated. However, once the DOM chang ...

Intermittent occurrence of (404) Not Found error in the SpreadsheetsService.Query function

Using the Spreadsheet API, I frequently update various sheets. Occasionally, and without any pattern, the SpreadsheetsService.Query function returns a (404) Not Found error. This issue does not seem to be related to internet connectivity or server downti ...

Using the onClick function to set attributes in React JS

I am currently working with 2 functions: addBookmark() and removeBookmark(). There is a variable called IsBookmarked that can be either true or false. In my JSX code related to bookmarks, it looks like this: {props.singleCompany.IsBookmarked ? ( ...

Node.js halted execution of NPM command due to insufficient memory

Just started working with nodejs and encountered some errors when using the npm command: $ npm install express --save Error: ENOMEM: not enough memory, scandir '/home/buraqtechno' <--- Last few GCs ---> [32765:0x23f0eb0] 216 ms: Mark ...

Angular animations are failing to function in the Visual Studio 2017 template

I am facing a challenge with incorporating animations in Angular 2 using Visual Studio 2017. I believe there must be a simple solution that I am overlooking at the moment. My goal is to animate certain elements and I have been testing the animations by tri ...

Using Swig template, React, and Express for server-side rendering

After setting up the router with Express, here is the code: var r = require('rethinkdb'); var quotes = require('../model/quotes'); var user = require('../model/users'); var auth = require('../lib/auth'); var React=r ...

Time picker in Bootstrap - Ensuring end time is not earlier than start time validation

How to prevent users from selecting a past time for the end time in Bootstrap time picker with start time validation <html> <head> </head> <body> <link href="https://maxcdn.bootst ...

Partial data is being received from the Ajax call

I currently have a textarea and a button on my webpage <textarea id="xxx" class="myTextArea" name="Text1" cols="40" rows="15">@ViewData["translation"]</textarea> <input type="button" id="convert-btn" class="btn btn-primary" value="Convert t ...

Adjust Title Padding Specifically for Mobile Devices

When viewing my blog page on mobile, I noticed that the titles of my blog posts are overlapping with the teasers. To fix this issue, I attempted to add margins to the bottom of the post titles specifically for mobile: https://i.stack.imgur.com/BHi3C.png H ...

Optimizing Backend Access with Laravel and Vue JS: How to Choose the Most Effective Approach

Currently, I am utilizing Laravel API passport to handle authentication in my Single Page Application (SPA) built with Vue. At the moment, whenever I need to access the backend server, I have to include a header in order to be allowed through the protected ...

The standard setting for inherent characteristics

In my React application, I have the following setup: export const MyView(props: { var1: boolean, var2: string}) => { /* do things here */ } class MyClass extends React.Component<MyProps, {}> { render() { // ... <MyView var ...

Tips for horizontally aligning a modal with smooth transition effects using Material UI and ensuring it is responsive

Struggling to center a modal with transition using Material UI and facing challenges with responsiveness on small screens, particularly mobile devices. The modal looks good and is centered on smaller screens if no transition is used. However, when a trans ...

How can I create a semantic-ui dropdown with a dynamically generated header?

Here are the dropdown options: const options = [ { key: '1', text: 'Example 1', value: 'Example 1', type:'ABC' }, { key: '2', text: 'Example 2', value: 'Example 2', t ...

Deploying a pair of GitHub repositories to a unified Azure web application

Although this isn't exactly a technical question, I couldn't find a more appropriate stackexchange site for it. Recently, I made the move to Azure for deploying my backend web applications and APIs. I discovered that it's possible to deploy ...

Struggling with identifying errors in the Javascript code for my assignment

My code is giving me trouble and I could really use some assistance You can find my code in this GitHub folder: link. To see the project in action, visit this page on GitHub Pages: link. The task involves iterating over an array of names and printing eit ...

Regular expressions: Capturing characters that come after and before a designated symbol

Is there a way to extract all letters, both before and after an underline "_", in JavaScript using Regex while excluding specific words like "pi", "\Delta" and "\Sigma"? How can this be achieved in Regex JS? /\b([^e|_|\d|\W])&bso ...