오늘은 다음과 같은 text input 컴포넌트를 만들어보고자 합니다.
텍스트 입력 시, 줄바꿈이 자동으로 되는 컴포넌트를 만들어보겠습니다.
어떤 태그를 써야할까?
일반적으로 <input type="text" /> 를 사용하지만, 줄바꿈 기능을 지원하지 않습니다. 때문에 <textarea /> 태그를 사용합니다.
문제점
textarea tag 를 사용하게 되면, 기본적으로 줄바꿈을 해줍니다. 그러나, 자신의 height 이상으로 글 길이가 늘어나면 스크롤이 생기게 됩니다. height 이상으로 영역이 늘어나지 않습니다.
해결방법
텍스트 입력시 줄바꿈이 생길 경우, textarea 영역의 height를 자동으로 늘려주는 JavaScript 코드를 넣어줍니다.
원리는 이렇습니다.
- textarea 영역의 height 을 1px로 줄여버립니다. 그러면 내부에 있는 글자 영역이 모두 스크롤영역이 되버립니다.
- 이때 textarea 엘리먼트의 scrollHeight 속성을 읽어옵니다. scroll 영역의 높이 값 입니다.
- 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);
}
}
'프론트엔드' 카테고리의 다른 글
접었다 폈다. 자연스러운 Accordian UI 만들기! (1) | 2024.02.14 |
---|---|
Sentry 를 알아보자 - (2) Transaction, Span 직접 생성해보기 (0) | 2024.02.05 |
Sentry 를 알아보자 - (1) Trace, Transaction, Span 이란? (0) | 2024.02.04 |
모노레포의 개념, 장단점, 종류 (1) | 2024.02.01 |
Docker-Compose Nginx, Certbot 컨테이너로 HTTPS 웹서버 설정하기 (0) | 2022.01.23 |