[React] Trim text to fit the DOM area and display a three-point reader.

There was a requirement for React to crop text to a specific size and display a three-point reader, which was implemented.

目次

Trim the text in the DOM area and display a three-point leader.

Implement as a component of React.

Definition of variables

Define useState to manage the text state to be trimmed and useRef to manage the target DOM region.

  const containerRef = useRef<HTMLDivElement>(null)
  const [text, setText] = useState("");
  //  A string that is variable according to user input. Essentially, it should be passed from the component.
  const title = "text_title";

Functions for trimming text.

Implement the textTrim function.

The DOM width usedRef and the character width of the target text are acquired at the timing of the call.
The width is compared and if it exceeds the DOM width, the target text is trimmed and a three-point leader string is added at the end.

  // Function to crop text to container size.
  const textTrim = useCallback(() => {
    if (!containerRef.current) return;

    //  DOM width to accommodate text
    const maxTitleWidth = containerRef.current.getBoundingClientRect().width;

    //  Width of text string
    const textCtx = document.createElement("canvas").getContext("2d");
    textCtx!.font = '16px "arial,sans-serif"';
    let textWidth = textCtx!.measureText(title).width;

    //  If the width exceeds the maximum width specified, the string is truncated.
    if (textWidth > maxTitleWidth) {
      let truncatedText = title;
      while (textWidth > maxTitleWidth && truncatedText.length > 0) {
        truncatedText = truncatedText.slice(0, -1);
        textWidth = textCtx!.measureText(truncatedText).width;
      }
      setText(truncatedText + "...");
    } else {
      //  If the width is within the maximum width, the original string is returned as is.
      setText(title);
    }
  }, [containerRef])

Firing the textTrim() function at the timing of resize.

Always calculate when the browser resizes for responsive support.

The resize event is defined in addEventListener and at initial drawing in useEffect.

  // リサイズ時に文字をトリムする
  useEffect(() => {
    textTrim();

    window.addEventListener("resize", textTrim);

    return () => {
      window.removeEventListener("resize", textTrim);
    }
  }, [])

entire code

The entire code is also included.

export default function TextTrimComponent() {
  const containerRef = useRef<HTMLDivElement>(null)
    const [text, setText] = useState("");
    // ユーザーインプットによって可変する文字列
    const title = "text_title";


  // テキストをコンテナサイズでトリミングする関数
  const textTrim = useCallback(() => {
    if (!containerRef.current) return;

    // テキストを収めるDOM横幅
    const maxTitleWidth = containerRef.current.getBoundingClientRect().width;

    // テキスト文字列の幅
    const textCtx = document.createElement("canvas").getContext("2d");
    textCtx!.font = '16px "arial,sans-serif"';
    let textWidth = textCtx!.measureText(title).width;

    // 幅が指定した最大幅を超えている場合、文字列を切り詰める
    if (textWidth > maxTitleWidth) {
      let truncatedText = title;
      while (textWidth > maxTitleWidth && truncatedText.length > 0) {
        truncatedText = truncatedText.slice(0, -1);
        textWidth = textCtx!.measureText(truncatedText).width;
      }
      setText(truncatedText + "...");
    } else {
      // 幅が最大幅以内の場合、元の文字列をそのまま返す
      setText(title);
    }
  }, [containerRef])

  // リサイズ時に文字をトリムする
  useEffect(() => {
    textTrim();

    window.addEventListener("resize", textTrim);

    return () => {
      window.removeEventListener("resize", textTrim);
    }
  }, [])

  return (
    <Container ref={containerRef}>
      <p>{text}</p>
    </Container>
  )
}

const Container = styled.div`
  background-color: #fff;
`

Summary

We have written a method for trimming with JavaScript, but if you can, it is recommended to implement it easily with CSS overflow, white-space properties, etc., as it is lighter.

p {
  width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Implementing it in JavaScript is complex and heavy, so it seems like a good idea to use it as a coping mechanism when it cannot be realised in CSS.

よかったらシェアしてね!
目次