Paul
Paul

Reputation: 197

Remove tooltip when scrolling a table

There is a table on one of the pages of the site. Some table cells have icons (from mui) with a tooltip. When you hover over the icon, a tooltip appears.

Here a problem arises: if the tooltip is open and the table is scrolled, then the tooltip flies out of the table borders.

Below is the code with the cell that contains the icon

    export default function TableCell() {
  return (
    <TableRow className="TableCellStyle">
      <TableCell>
        <Tooltip
          title="Download"
          arrow
          componentsProps={{
            tooltip: {
              sx: {
                bgcolor: "#a3a3a3",
                "& .MuiTooltip-arrow": {
                  color: "#a3a3a3"
                }
              }
            }
          }}
          PopperProps={{
            modifiers: [
              {
                name: "offset",
                options: {
                  offset: [0, -8]
                }
              }
            ]
          }}
        >
          <FileDownloadIcon />
        </Tooltip>
      </TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
    </TableRow>
  );
}

Tell me how to make the tooltip disappear if the table scrolls

Update: so far there was an answer that when hovering over the tooltip, the scrolling of the table would disappear altogether. But that doesn't quite work for me. I would like the tooltip to disappear as soon as the scroll starts.

Upvotes: 1

Views: 2196

Answers (2)

Omar Siddiqui
Omar Siddiqui

Reputation: 1655

Import useEffect() from React and add this function to the FileDownloadButton.jsx component:

Method 1: Using basic JS

useEffect(() => {
    const scrollableElements = [
      document.querySelector(".TableBodyStyle"),
      document
    ];
    scrollableElements.forEach((element) => {
      element.addEventListener("scroll", (event) => {
        const tooltip = document.querySelector("[role='tooltip']");
        if (tooltip) {
          tooltip.style.display = "none";
        }
      });
    });
  });

What we're doing is checking to see if the tooltip is visible, and if it is, we're setting the display to none when the table is scrolled.

A cleaner way would be to call the Tooltip's inbuilt hide function, that way you would retain the hiding animation. I've not used React before though, so I'm unsure of how to programmatically call the functions of a child component. If you know how to do that, you can substitute the code inside the listener with that function call instead.

Here's what the current method looks like: https://codesandbox.io/s/festive-ritchie-f9jizd?file=/src/FileDownloadButton.jsx

Edit

Method 2: Using React state

So I did a bit of reading and was able to figure out how to solve this issue using react state. It is almost the same as above, we just need to create a state variable and setter function, and call the setter inside the eventHandler.

This is what it'll look like:

const [showTooltip, setShowTooltip] = useState(false);
  useEffect(() => {
    const scrollableElements = [
      document.querySelector(".TableBodyStyle"),
      document
    ];
    scrollableElements.forEach((element) => {
      element.addEventListener("scroll", (event) => {
        setShowTooltip(false)
      });
    });
  });

For this method you will also need to pass these values as props to the Tooltip component.

<Tooltip
    title="Show item"
    arrow
    open={showTooltip}
    onOpen={()=> { setShowTooltip(true) }}
    onClose={()=> { setShowTooltip(false) }}
    componentsProps={{
      tooltip: {
        sx: {
          bgcolor: "#a3a3a3",
          "& .MuiTooltip-arrow": {
          color: "#a3a3a3"
          }
        }
      }
    }}
    PopperProps={{
      modifiers: [
        {
          name: "offset",
          options: {
            offset: [0, -8]
          }
        }
      ]
    }}
  >

This is what the new method would look like: https://codesandbox.io/s/hide-tooltip-using-react-6ctu7y?file=/src/FileDownloadButton.jsx

Upvotes: 1

Yash Sharma
Yash Sharma

Reputation: 181

Here is one possible solution:

Strategy: Use a state variable to define when you want the table body to be scroll-able and when not to. On enter and exit of hover you can toggle the state and apply conditional styling to html.

Sandbox link: https://codesandbox.io/s/confident-margulis-25h1gh?file=/src/DevicesTableCell.jsx

Code:


export default function DevicesTableCell({ setAllowScroll }) {
  return (
    <TableRow className="TableCellStyle">
      <TableCell>
        <Tooltip
          title="Download item"
          arrow
          onOpen={() => {
            setAllowScroll(false);
          }}
          onClose={() => {
            setAllowScroll(true);
          }}
          componentsProps={{
            tooltip: {
              sx: {
                bgcolor: "#a3a3a3",
                "& .MuiTooltip-arrow": {
                  color: "#a3a3a3"
                }
              }
            }
          }}
          PopperProps={{
            modifiers: [
              {
                name: "offset",
                options: {
                  offset: [0, -8]
                }
              }
            ]
          }}
        >
          <FileDownloadIcon />
        </Tooltip>
      </TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
    </TableRow>
  );
}

export default function DevicesTable() {
  const [allowScroll, setAllowScroll] = useState(true);
  return (
    <TableContainer className="TableContainerGridStyle">
      <Table className="TableStyle">
        <DevicesTableHeader />
        <TableBody
          className="TableBodyStyle"
          style={!allowScroll ? { overflow: "hidden" } : {}}
        >
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
          <DevicesTableCell setAllowScroll={setAllowScroll} />
        </TableBody>
      </Table>
    </TableContainer>
  );
}

Upvotes: 1

Related Questions