프론트엔드

줄바꿈 되는 Input Text ( Textarea ) 입력창 만들기

CodeBoyEd 2024. 2. 9. 15:34

오늘은 다음과 같은 text input 컴포넌트를 만들어보고자 합니다.

텍스트 입력시 줄바꿈이 자동으로 되는 컴포넌트

 

텍스트 입력 시, 줄바꿈이 자동으로 되는 컴포넌트를 만들어보겠습니다.

 

어떤 태그를 써야할까?

일반적으로 <input type="text" /> 를 사용하지만, 줄바꿈 기능을 지원하지 않습니다. 때문에 <textarea /> 태그를 사용합니다.

 

문제점

textarea tag 를 사용하게 되면, 기본적으로 줄바꿈을 해줍니다. 그러나, 자신의 height 이상으로 글 길이가 늘어나면 스크롤이 생기게 됩니다. height 이상으로 영역이 늘어나지 않습니다.

해결방법

텍스트 입력시 줄바꿈이 생길 경우, textarea 영역의 height를 자동으로 늘려주는 JavaScript 코드를 넣어줍니다.

원리는 이렇습니다.

  1. textarea 영역의 height 을 1px로 줄여버립니다. 그러면 내부에 있는 글자 영역이 모두 스크롤영역이 되버립니다.
  2. 이때 textarea 엘리먼트의 scrollHeight 속성을 읽어옵니다. scroll 영역의 높이 값 입니다.
  3. textarea 영역의 높이를 scrollHeight 값으로 변경해줍니다.

전체 코드를 보면 다음과 같습니다.

 

"adjustTextareaHeight" 함수가 위에서 말한 1~3 번을 수행하는 로직입니다.

export default function Text({ placeholder, value, onChange, invalidMsg }: IText) {
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);

  const adjustTextareaHeight = () => {
    const textarea = textareaRef.current;
    if (textarea) {
      textarea.style.height = '1px';
      textarea.style.height = `${textarea.scrollHeight}px`;
    }
  };

  const onInput: FormEventHandler<HTMLTextAreaElement> = (e) => {
    const textarea = textareaRef.current;
    if (!textarea) return;

    const inputValue = (e.target as HTMLTextAreaElement).value;
    if (inputValue.match(/^\s+/)) {
      textarea.value = '';

      return;
    }

    onChange(inputValue);
    adjustTextareaHeight();
  };

  const onBlur = () => {
    const textarea = textareaRef.current;
    if (!textarea) return;

    const trimmed = textarea.value.trim();
    onChange(trimmed);
    adjustTextareaHeight();
  };

  return (
    <div className={style.txt_wrap}>
      <textarea
        className={invalidMsg ? style.invalid : ''}
        placeholder={placeholder}
        value={value}
        onInput={onInput}
        onBlur={onBlur}
        ref={textareaRef}
      />
      {invalidMsg && <p className={style.invalid_msg}>{invalidMsg}</p>}
    </div>
  );
}

 

textarea 에 적용한 CSS 는 다음과 같습니다.

textarea {
  display: block;
  width: 100%;
  border: none;
  outline: none;
  resize: none;
  overflow: hidden;
  font-size: 18px;
  font-weight: 500;
  line-height: 24px;
  padding-bottom: 10px;
  height: 34px;
  border-bottom: var(--gray-100) solid 1px;

  &:focus {
    border-bottom: var(--main-color) solid 2px;
  }

  &.invalid {
    border-bottom: var(--err-color) solid 1px;
  }

  &::placeholder {
    color: var(--gray-200);
  }
}