2

I have a component that gets a dynamic text. I am showing ellipsis when the text overflows the width of div. Now, I am showing a show more and when user clicks on it, I am showing the entire text and show show less link.

import React from "react";
import "./styles.css";

export default function App(props) {
  const [showMore, setShowMore] = React.useState(true);
  const onClick = () => {
    setShowMore(!showMore);
  }
  return (
    <>
      <div className={showMore ? '' : "container"}>{props.text}</div>
      <span className="link" onClick={onClick}>{showMore ? 'show less' : 'show more'}</span>
    </>
  );
}

.container {
  overflow-x: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block !important;
  width: 250px;
  background-color: #eaeaea;
}

enter image description here

enter image description here

The code above shows show more link even if the text doesn't overflow.

enter image description here

But I want to show show more link only when text overflows. How can I achieve that?

EDIT

From crays' comment I found this stackoverflow anwser

Now, I tried using a ref to access the styles as following

import React from "react";
import "./styles.css";

export default function App(props) {
  const [showMore, setShowMore] = React.useState(false);
  const onClick = () => {
    setShowMore(!showMore);
  };

  const checkOverflow = () => {
    const el = ref.current;
    const curOverflow = el.style.overflow;

    if ( !curOverflow || curOverflow === "visible" )
        el.style.overflow = "hidden";

    const isOverflowing = el.clientWidth < el.scrollWidth 
        || el.clientHeight < el.scrollHeight;

    el.style.overflow = curOverflow;

    return isOverflowing;
  };

  const ref = React.createRef();

  return (
    <>
      <div ref={ref} className={showMore ? "container-nowrap" : "container"}>
        {props.text}
      </div>
      {(checkOverflow()) && <span className="link" onClick={onClick}>
        {showMore ? "show less" : "show more"}
      </span>}
    </>
  )
}

I also tried using forwardref

export const App = React.forwardRef((props, ref) => {
  const [showMore, setShowMore] = React.useState(false);
  const onClick = () => {
    setShowMore(!showMore);
  };

  const checkOverflow = () => {
    const el = ref.current;
    const curOverflow = el.style.overflow;

    if (!curOverflow || curOverflow === "visible") el.style.overflow = "hidden";

    const isOverflowing =
      el.clientWidth < el.scrollWidth || el.clientHeight < el.scrollHeight;

    el.style.overflow = curOverflow;

    return isOverflowing;
  };

  return (
    <>
      <div ref={ref} className={showMore ? "container-nowrap" : "container"}>
        {props.text}
      </div>
      {checkOverflow() && (
        <span className="link" onClick={onClick}>
          {showMore ? "show less" : "show more"}
        </span>
      )}
    </>
  );
});

But I am getting an error Cannot read property 'style' of null

troglodyte07
  • 3,598
  • 10
  • 42
  • 66
  • Does this answer your question? [Determine if an HTML element's content overflows](https://stackoverflow.com/questions/143815/determine-if-an-html-elements-content-overflows) – Cray Mar 19 '20 at 09:55
  • @Cray yes. But how do I pass the el to the function? – troglodyte07 Mar 19 '20 at 10:04
  • Check this ...https://stackoverflow.com/questions/35170581/how-to-access-styles-from-react – M A Salman Mar 19 '20 at 10:26

2 Answers2

0

Check out this article, which uses "checkbox hack" to do it.

splintor
  • 9,924
  • 6
  • 74
  • 89
-3

I think you may go with another approach, instead of depending on what is happening visually inside the browser

let's say the text will only overflow when you have more than N char (define this number by your self) for example 100 char

import {useState} from 'react';

export const Accordion = ({ text, limit = 100 }) => {
  const isExpandable = text.length > limit;
  const [viewText, setViewText] = useState(
    isExpandable ? text.slice(0, limit) : text
  );
  const isExpanded = text.length === viewText.length;
  return (
    <>
      <p>{viewText}</p>
      {isExpandable && (
        <button
          onClick={() => setViewText(isExpanded ? text.slice(0, limit) : text)}
        >
          {isExpanded ? "show less" : "show more"}
        </button>
      )}
    </>
  );
};

code sand box link here