TextField 데모
TextFieldSingleLine·TextFieldMultiLine는 라벨·필드·도움말을 묶을 수 있는 DS 텍스트 필드입니다. id는 입력 요소 식별·접근성 연결에 쓰이며, 라벨이 있을 때 htmlFor와 맞춥니다.
import
default export : TextFieldSingleLine, TextFieldMultiLine
inner 필드 ( inputProps / textareaProps 에 맞는 타입 ) : SingleLineInputProps, MultiLineTextareaProps
라벨+필드+도움말 블록 전체 ( 컴포넌트 루트에 넣는 props ) : TextFieldSingleLineProps, TextFieldMultiLineProps — 래퍼·폼에서 React.ComponentProps<typeof …> 등에 쓰기 좋습니다.
import TextFieldSingleLine from "@/shared/components/ds/TextField/SingleLine";
import type {
SingleLineInputProps,
TextFieldSingleLineProps,
} from "@/shared/components/ds/TextField/SingleLine";
import TextFieldMultiLine from "@/shared/components/ds/TextField/MultiLine";
import type {
MultiLineTextareaProps,
TextFieldMultiLineProps,
} from "@/shared/components/ds/TextField/MultiLine";
// 래퍼에 타입을 줄 때 (예: 폼 field 컴포넌트)
function example(props: TextFieldSingleLineProps) {
return <TextFieldSingleLine {...props} />;
}
function exampleMulti(props: TextFieldMultiLineProps) {
return <TextFieldMultiLine {...props} />;
}SingleLine — 기본
`inputProps`에 `placeholder`, `clearable` 등을 넘깁니다.
<TextFieldSingleLine
label="레이블"
id="field-id"
inputProps={{
placeholder: "플레이스 홀더",
clearable: true,
}}
description="도움말"
/>도움말
SingleLine — 라벨·도움말 없음, 클리어 없음
label·description을 생략할 수 있고, 지우기 버튼은 inputProps.clearable: false로 끕니다.
<TextFieldSingleLine
id="field-minimal"
inputProps={{
placeholder: "라벨·도움말 없음, 클리어 없음",
clearable: false,
"aria-label": "검색",
}}
/>MultiLine — 기본
`textareaProps`에 `maxLength`를 주면 하단에 글자 수가 표시됩니다. `showCount: false`로 끌 수 있습니다.
<TextFieldMultiLine
label="레이블"
id="field-id"
textareaProps={{
placeholder: "플레이스 홀더",
maxLength: 300,
}}
description="도움말"
/>도움말
MultiLine — 라벨·도움말 없음, 글자 수 없음
label·description을 생략할 수 있고, 하단 글자 수는 textareaProps.showCount: false로 끕니다. maxLength는 입력 제한만 줄 때도 같이 쓸 수 있습니다.
<TextFieldMultiLine
id="field-ml-minimal"
textareaProps={{
placeholder: "라벨·도움말 없음, 글자 수 표시 없음",
showCount: false,
maxLength: 500,
"aria-label": "본문",
}}
/>SingleLine — 제어 (value + onChange)
`inputProps`에 `value` / `onChange`를 넘기면 제어 컴포넌트로 동작합니다.
const [value, setValue] = useState("");
<TextFieldSingleLine
label="레이블"
id="controlled-sl"
inputProps={{
value,
onChange: (e) => setValue(e.target.value),
placeholder: "제어 예시",
}}
description="상위 state와 연동"
/>상위 state와 연동
현재 값: «빈 문자열»
문자 정책 — 유니코드 기호/이모지 차단
공통 컴포넌트 API에 연결하기 전, 순수 입력 정책 유틸만 controlled field에서 확인합니다.
import {
sanitizeTextInputValue,
TEXT_INPUT_POLICY,
} from "@/shared/lib/textInputPolicy";
const policy = TEXT_INPUT_POLICY.multilingualTextWithoutUnicodeSymbols;
<TextFieldSingleLine
label="정책 테스트"
id="policy-test"
inputProps={{
value,
onChange: (e) =>
setValue(sanitizeTextInputValue(e.target.value, policy)),
}}
/>허용: 모든 언어 문자, ASCII 문자, :hearts: / 차단: 실제 기호·이모지·비ASCII 문장부호
현재 값: «빈 문자열»
문자 수 기준 — 보이는 글자 수
이모지를 허용하는 제한 없는 필드에서 `String.length` 대신 사용자에게 보이는 글자 수 기준을 확인합니다.
import { getTextInputLength } from "@/shared/lib/textInputPolicy";
const visibleLength = getTextInputLength(value);수업명처럼 제한 없는 입력에서 이모지 포함 카운트를 확인합니다.
보이는 글자 수: 0 / JS length: 0
수업명 예시 — 모든 문자 허용 + 50자 제한
수업명처럼 문자 제한이 없는 필드에 최대 글자 수만 필요한 경우, sanitize 없이 보이는 글자 수 기준으로 자릅니다.
import {
getTextInputLength,
truncateTextInputValue,
} from "@/shared/lib/textInputPolicy";
const COURSE_NAME_MAX_LENGTH = 50;
<TextFieldSingleLine
label="수업명"
id="course-name"
inputProps={{
value,
onChange: (e) =>
setValue(truncateTextInputValue(e.target.value, COURSE_NAME_MAX_LENGTH)),
// native maxLength는 넣지 않음
}}
description={`${getTextInputLength(value)}/${COURSE_NAME_MAX_LENGTH}`}
/>0/10 · 예시는 빠른 확인을 위해 10글자로 제한
현재 값: «빈 문자열»
에러 / 성공 (SingleLine)
`error` 또는 `success`로 테두리·라벨·도움말 색이 바뀝니다. `error`가 `success`보다 우선합니다.
<TextFieldSingleLine
label="레이블"
id="field-id"
error
inputProps={{ placeholder: "…" }}
description="도움말"
/>
<TextFieldSingleLine
label="레이블"
id="field-id-2"
success
inputProps={{ placeholder: "…" }}
description="도움말"
/>도움말
도움말
비활성
`disabled`는 라벨·필드·도움말이 있는 블록 전체에 적용됩니다.
<TextFieldSingleLine
label="레이블"
id="field-id"
disabled
inputProps={{ placeholder: "…", clearable: true }}
description="도움말"
/>
<TextFieldMultiLine
label="레이블"
id="field-id-2"
disabled
textareaProps={{ placeholder: "…", maxLength: 300 }}
description="도움말"
/>도움말
도움말
