How to display an icon when there are more than 3 lines in <td>

37 views Asked by At


I'm trying to display a SVG icon in a table cell when there are more than 3 lines of text in a table cell.

The text data for this table body looks like this:

  const bodyData = [
    <>Cell 1</>,
    <>
      <ul>
        <li>Cell 2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum ante eget massa rhoncus
      tincidunt.</li>
      </ul>
    </>,
    <>Cell 3</>,
    <>
      Cell 4 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum ante eget massa rhoncus
      tincidunt. Nullam vestibulum euismod justo, vitae bibendum enim auctor nec. Integer a lorem
      nec nibh tincidunt volutpat. Duis non consequat erat.
    </>,
  ];

And it maps this data like this:

     <tbody>
       <tr>
         {bodyData.map((text, index) => (
           <td>
             <Content>{text}</Content>
           </td>
         ))}
       </tr>
     </tbody>

I've tried a resize observer using a scroll height and client height like this:


useEffect(() => {
    const textElements = document.querySelectorAll('.text-container');
    if (textElements.length > 0) {
      resizeObserver.current = new ResizeObserver(entries => {
        entries.forEach(entry => {
          const truncated = entry.target.scrollHeight > entry.target.clientHeight;
           // How can I change this logic to detect if it's more than 3 lines...
          if (truncated) {
             // TODO: logic to display an icon
          }
        });
      });

      textElements.forEach(textElement => {
        resizeObserver.current?.observe(textElement);
      });
    }

    return () => {
      if (resizeObserver.current) {
        resizeObserver.current.disconnect();
      }
    };
  }, []);

Which is wrong. I'm stucked. I am really out of idea of how to detect if this text in each table cell is more than 3 lines.

I named the variable truncated because I also want to make the text truncated when it's more than 3 lines of text. But I found it'll be achievable with css (line clamps). I'd appreciate if anyone could help me out to solve this. Thank you.

1

There are 1 answers

1
Qasim On

so to determine if the text in any table cell is longer than 3 characters, you can use a combination of clientHeight, scrollHeight, and line-height. try the code below.

useEffect(() => {
  const textElements = document.querySelectorAll('.text-container');

  if (textElements.length > 0) {
    resizeObserver.current = new ResizeObserver(entries => {
      entries.forEach(entry => {
        const lineHeight = parseInt(window.getComputedStyle(entry.target).lineHeight);
        const numberOfLines = Math.floor(entry.target.clientHeight / lineHeight);

        // Check if the number of lines is greater than 3
        if (numberOfLines > 3) {
          // TODO: logic to display an icon
          console.log('More than 3 lines');
        }
      });
    });

    textElements.forEach(textElement => {
      resizeObserver.current?.observe(textElement);
    });
  }

  return () => {
    if (resizeObserver.current) {
      resizeObserver.current.disconnect();
    }
  };
}, []);

so basically we are calculating the character height of the character store and then divide the client height by the character height to determine the number of characters. If the rows are more than 3, you can use your logic to display the icon.

Note: makesure that the line height is the same for the text in the table cells, as the calculation is based on the exact line height value.

:)