1

I have a card like this:

enter image description here

<Card className="m-5 border-0 shadow" style={styles.card}>
  <Row>
    <Col>
      <Card.Img src={require("../assets/images/findingsPage/EnglishesOfTheWorld.jpg")} style={styles.cardImage} />
    </Col>
    <Col>
      <Card.Body>
      <Card.Title as="h1">Englishes of the World</Card.Title>
      <Card.Text as="h4" style={styles.cardText}>
        How do your grammar intuitions depend on when and where you learned English? Participants took a short grammar quiz, which we are using to understand how grammar differs in different parts of the English-speaking world (USA, Ireland, Australia, etc.). We are also investigating how grammar is different for people who learn English later in life: Do they make different mistakes if their first language is German as opposed to Japanese?
      </Card.Text>
      </Card.Body>
    </Col>
  </Row>
</Card>

Is there a way that I can collapse part of the text if the text length goes beyond the card height like this: https://mdbootstrap.com/plugins/jquery/extended-cards/

enter image description here

enter image description here

Thanks.

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Rui Han
  • 77
  • 1
  • 3
  • 12

1 Answers1

3

Let's start with the demo: https://codesandbox.io/s/cool-wright-u5old?file=/src/App.js

The logic is this:

  • On component mounted, use a ref to identify if the text parent's height is greater than your limit
  • If so, set max-height (will get to it) as the limit and show the toggle button
  • When the user clicks on that button, it toggles max-height between the limit and the max possible height of the card.

The reason for using max-height is because of the transition. It's the only way to do css only transition of height.

For the convenience, I extracted this logic into a new Component, but it can be done inside the original component.

And now, to the code:

const MAX_POSSIBLE_HEIGHT = 500;

const ExpendableText = ({ maxHeight, children }) => {
  const ref = useRef();
  const [shouldShowExpand, setShouldShowExpand] = useState(false);
  const [expanded, setExpanded] = useState(true);

  useEffect(() => {
    if (ref.current.scrollHeight > maxHeight) {
      setShouldShowExpand(true);
      setExpanded(false);
    }
  }, [maxHeight]);

  return (
    <Card.Text as="h4" style={styles.cardText} ref={ref}>
      <div
        class="inner"
        style={{ maxHeight: expanded ? MAX_POSSIBLE_HEIGHT : maxHeight }}
      >
        {children}
      </div>
      {shouldShowExpand && (
        <button onClick={() => setExpanded(!expanded)}>Expand</button>
      )}
    </Card.Text>
  );
};

And the css part

.inner {
  overflow: hidden;
  transition: max-height 0.2s ease;
}

Finally, the component can be consumed like this:

<ExpendableText maxHeight={95}>
  How do your grammar intuitions depend on when and where you
  learned English? Participants took a short grammar quiz, which
  we are using to understand how grammar differs in different
  parts of the English-speaking world (USA, Ireland, Australia,
  etc.). We are also investigating how grammar is different for
  people who learn English later in life: Do they make different
  mistakes if their first language is German as opposed to
  Japanese?
</ExpendableText>
  • I'v included an height transition in the solution (because I like it). If you don't need the transition, the solution will be a bit shorter.
  • If there is no need to calculate the height because the content will always has to cut, the solution will be easier.
Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
  • Thanks. It's a great solution. And I also find the Accordion component in react-bootstrap: https://react-bootstrap.github.io/components/accordion/ – Rui Han May 06 '20 at 05:02