skip to Main Content

I am generating multiple words from a JSON file and want to display only two lines at once, currently I am using line clamps but it truncates the last word of the second line. If the word is being truncated I want it to move to the next line. Is it possible to implement this?

                 <div className="box">
                    <p className="word">
                        {wordList.map((word, wordIndex) => {
                            const currWord = typedHistory[wordIndex] || "";
                            const isCurrentWord = wordIndex === typedHistory.length;
                            const hasWrongChars = currWord.split("").some((char, index) => char !== word[index]);
                            const isExcessLength = currWord.length > word.length;
                            const isIncomplete = currWord.length >= 0 && currWord.length < word.length && typedHistory.includes(currWord);
                            const shouldHighlightWordRed = hasWrongChars || isExcessLength || isIncomplete;
                            return (
                                <span key={wordIndex} ref={isCurrentWord ? currentWordRef : null}>
                                    {word.split("").map((char, charIndex) => {
                                        let charColor = "#fff";

                                        if (wordIndex < typedHistory.length) {
                                            charColor = shouldHighlightWordRed ? "red" : "var(--main-color)";
                                        } else if (isCurrentWord) {
                                            const typedChar = typedChars[charIndex] || "";
                                            charColor = typedChar === char ? "var(--main-color)" : typedChar !== "" ? "red" : "#fff";
                                        }
                                        return (
                                            <span key={charIndex} style={{ color: charColor }}>{char}</span>
                                        );
                                    })}
                                    {' '}
                                </span>
                            );
                        })}
                    </p>
                </div>

CSS:

.box {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  background-color: var(--sub-alt-color);
  border-radius: 10px;
  max-height: 8.5em;  
  height: 8.5em;
  user-select: none;

}
.box .word {
  display: block;
  font-size: 1.5rem;
  overflow-y: hidden;
  line-height: 1.8em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
          line-clamp: 2; 
  -webkit-box-orient: vertical;
}

How I am generating text

 useEffect(() => {
        import("../../public/english.json").then((words) =>
            dispatch(setWordList(words.default))
        );
    }, [dispatch]);

I am expecting the behavior of text like in this case: typetest.io

Here is a reproducible example: codesandbox

2

Answers


  1. Chosen as BEST ANSWER

    I found a solution by removing line-clamp and making max-height = 2*line-height

    import { useEffect, useRef, useState } from "react";
    import "./styles.css";
    
    export default function App() {
      const inputRef = useRef(null);
      const currentWordRef = useRef(null);
      const [wordList, setWordList] = useState([]);
    
      useEffect(() => {
        import("./english.json").then((words) => setWordList(words.default));
      });
      return (
        <div
          style={{
            display: "flex",
            width: "100%",
            justifyContent: "center",
            backgroundColor: "green",
          }}
        >
          <div className="test">
            <div className="box">
              <p className="word">
                {wordList.map((word, wordIndex) => {
                  return (
                    <span key={wordIndex}>
                      {word.split("").map((char, charIndex) => {
                        let charColor = "#fff";
                        return (
                          <span key={charIndex} style={{ color: charColor }}>
                            {char}
                          </span>
                        );
                      })}{" "}
                    </span>
                  );
                })}
              </p>
            </div>
          </div>
        </div>
      );
    }
    
    .test {
      display: flex;
      flex-direction: column;
      justify-content: center;
      height: 62vh;
      padding-left: 20px;
      padding-right: 20px;
      gap: 10px;
      max-width: 58rem;
      width: 58rem;
    }
    
    .box {
      padding-left: 1.5rem;
      padding-right: 1.5rem;
      border-radius: 10px;
      height: 8.5em;
      user-select: none;
      overflow: hidden; /* Hide overflow */
    }
    
    .box .word {
      overflow-wrap: break-word;
      word-wrap: break-word;
      word-break: break-word;
      white-space: normal; /* Ensure words wrap correctly */
      line-height: 1.5em;
      max-height: 3em; /* Limit to 2 lines */
      overflow: hidden; /* Hide overflow beyond the second line */
    }
    
    .box .word {
      display: inline-block;
    }
    

    Here is the demo


  2. You can simply set the block height to 2lh and overflow:hidden. Showed the difference in the example:

    div {
      width: 248px;
      margin-bottom: 12px;
      outline: solid;
      overflow: hidden;
      &:nth-child(1) {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
      }
      &:nth-child(2) {
        height: 2lh;
      }
    }
    <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, commodi!</div>
    <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, commodi!</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search