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

Is there a way to access and parse a CSV file from a URL within a Next.js project?

Currently working on a Next.js application available here. The task at hand requires reading a CSV file from a specific URL within the same repository in multiple instances. Unfortunately, I am encountering difficulties retrieving this data. You can locate ...

Is the information not displayed in its entirety on the FullCalendar?

I'm currently working with the following code: $('#calendar_1').fullCalendar({ header : { left : 'prev,next today', center : 'title', right : 'month,agendaWeek,agendaDay' ...

Ways to show dropdown menu link exclusively on mobile browsers and not on desktop browsers

<li class="megamenu-content"> <div class="megamenu-content-wrapper clearfix"> <ul class="col-lg-3 col-sm-3 col-md-3 "> <li class="cat-header">DISPLAY MEMBERS</li> ...

Adjust the size of the buttons based on the width of the screen

I have successfully implemented a dropdown menu with both text and an icon. However, I am now faced with the challenge of removing the text while retaining the icon when the screen width is reduced to a maximum of 768px. Is it possible to modify the conten ...

React Dependency Error

Allow me to outline my current situation: I integrated the react-native-multiple-select-list package into my react-native project by executing: 'yarn add react-native-multiple-select-list': "dependencies": { "react-native-multiple-select ...

Developing an npm console application that is "installable" similar to tools like yeoman, gulp, or grunt

Recently dipping my toes into the world of NPM, I've been itching to create a package that functions as a console app (think gulp and grunt). My goal is simple: I want users to be able to run npm install -g mypackage followed by mypackage This sh ...

Dispatch in React Redux is not intercepted

I've been grappling with this issue for hours and still can't seem to find a solution. When I click the button, the function "getLocation" is being triggered (Confirmed it) However, the dispatch is not getting passed to the reducer. After r ...

When attempting to set a dynamic src tag for embedding a Google Map in a React application, an X-Frame-Options

I'm attempting to display a specific location using an iframe embed from Google Maps (shown below): <iframe width="100%" height="200" frameBorder="0" scrolling="no" marginHeight={0} marginWidth={0} id="g ...

Is there a way to convert my function into a variable in order to execute an array of statements

I'm struggling to convert this code into a variable. I need to bind it inside a statement execute array. This is the code I am working on, which retrieves the current date and timezone. I attempted using $date = function() {}, echo $date(); but that ...

Connecting the value of one input to influence another input

There are two input boxes provided - one for current address and another for permanent address. When the checkbox is clicked, the value of the current address should be displayed in the permanent address box. However, I am facing an issue where when I unc ...

Creating a TypeScript declaration for the Cypress configuration file

When attempting to transition a setup-helper file to a ts definition, I encountered the following error message: Property 'domainName' does not exist on type 'Config' The error is related to this specific line of code: const { domainNa ...

Can an inline try be implemented without including a catch block as demonstrated?

I have a scenario where I need to execute code that may result in an error without catching it. If the response is not valid JSON, then the desired outcome should be 0: Here is the code snippet I am considering: var overallProgress = try {JSON.parse(text ...

Enhance your website with a stylish CSS jQuery menu that lets you toggle, slide

If you're curious about the code, take a look here! Here are some of the issues I'm facing: The div doesn't toggle to hide when clicked on itself, only when another one is clicked. (UPDATE: it actually won't toggle at all) When t ...

Exploring a different approach to utilizing Ant Design Table Columns and ColumnGroups

As per the demo on how Ant Design groups columns, tables from Ant Design are typically set up using the following structure, assuming that you have correctly predefined your columns and data: <Table columns={columns} dataSource={data} // .. ...

Am I utilizing the htmlspecialchars function properly?

My main objective is to protect the user from malicious code and prevent XSS attacks. I have implemented a series of checks to filter the user's input before storing it in the database. The user input is stored in the $post variable. $post = htmlspec ...

Tips for sorting out JSON data by specific key parameters and eliminating any redundant information

I am presenting a Json object with the following structure: var initialdata = [ { "type": "Feature", "properties": { "Region": "US", "SubRegion": "US-1", "SiteID&quo ...

Position the label and the select dropdown side by side within the sweetalert 2 component

Can anyone provide an example of aligning a label and dropdown in the same row using sweetalert2? I attempted to customize the label placement, but it appears on a separate line. I would like to log the selected dropdown item upon clicking the OK button. ...

Tips on accessing a specific value while customizing the Autocomplete feature in Material UI

I am working on implementing the autocomplete feature of Material UI, and I want to be able to capture the ID of the selected team when a selection is made. Currently, the code only fetches the name of the selected team. How can I retrieve the ID instead? ...

Guide on inserting HTML text box form input into Express route parameter

I'm currently working on implementing a feature that allows users to search through my mongo database using an endpoint structured like this: app.get('/search/:input', function(req, res){ console.log(`get request to: /members/${req.params ...

When the next button is clicked, the button content disappears

I am struggling with a problem involving two buttons that store tables. The issue is, I want the table to disappear when the second button is clicked and show the contents of the second button immediately after clicking it once, rather than having to click ...