Components
TextField
라벨, 입력 필드, 보조 텍스트를 하나로 묶은 폼 컴포넌트입니다.
Mobile
Web TextField와 anatomy(Label + Input + HelperText)는 동일, 모바일 키보드 동작이 추가된다.
- keyboardType: 입력 내용에 맞게 선택
- 일반 텍스트:
default - 이메일:
email-address(autoCapitalize="none",autoCorrect={false}) - 숫자:
number-pad, 통화는decimal-pad - 전화:
phone-pad - URL:
url(autoCapitalize="none")
- 일반 텍스트:
- secureTextEntry: 비밀번호는
secureTextEntry={true}— 우측 inline 토글로 보이기/숨기기 옵션 제공 권장 - autoCapitalize: 일반 이름·문장은
sentences또는words, 이메일·아이디·식별자는none - autoCorrect: 자유 텍스트는
true, 식별자·코드는false - autoComplete / textContentType: OS의 자동 채우기(비밀번호 매니저, OTP)와 연동. 예:
autoComplete="one-time-code",textContentType="oneTimeCode" - placeholder color:
stone-300(=DesignColors.warmGray[300]) - return key: 마지막 필드는
returnKeyType="done", 다음 필드로 이동이면"next".onSubmitEditing으로 명시적 처리 - 에러 표시: 에러 메시지는
text-rose-600, 입력 테두리는border-rose-300. 메시지는 입력 아래caption1Regular - 포커스 시 스크롤: 키보드에 가려지지 않도록 ScrollView/BottomSheet가 자동 스크롤 (BottomSheet 키보드 처리는 Dialog Mobile 참조)
- autoFocus: 사용자가 입력을 기대하는 명시적 진입(예: "이름 입력" 시트)에서만 — 일반 폼에선 사용자 탭 후 focus
Preview
Anatomy
┌──────────────────────────────────┐
│ Label text [옵션 *] │ ← Label
│ ┌────────────────────────────────┐│
│ │[prefix] Input value [suffix] ││ ← Input (prefix/suffix optional)
│ └────────────────────────────────┘│
│ Helper text or Error message │ ← HelperText
└──────────────────────────────────┘세 요소가 하나의 단위로 작동합니다. htmlFor / aria-describedby로 연결하여 스크린리더가 전체 맥락을 읽을 수 있게 합니다.
Variant
| Variant | Style | 사용 시점 |
|---|---|---|
outline | 1px solid stone-200 4면 테두리 + rounded-md | 기본. 폼에 여러 필드가 있을 때 |
underlined | 하단 1px solid stone-200만 + rounded-none + 투명 배경 | 화면에 입력 필드가 하나뿐일 때 |
States
| State | Border | Ring | Background |
|---|---|---|---|
default | stone-200 | — | white |
focus (일반) | brown-800 | — | white |
focus (핵심 폼) | brown-800 | ring-2 ring-brown-800/10 | white |
with value | stone-200 | — | white |
invalid | rose-400 | ring-2 ring-rose-500/10 | white |
disabled | stone-100 | — | stone-50 |
Focus ring 사용 기준
| Ring 없음 | Ring 있음 |
|---|---|
| 설정, 프로필 수정, 다이얼로그 내 폼 등 보조적 입력 | 로그인, 회원가입, 결제 등 사용자가 집중해야 하는 핵심 폼 |
| 화면에 필드가 여러 개 있어 ring이 과도하게 강조될 때 | 필드가 1–2개로 입력에 집중을 유도해야 할 때 |
disabled는 variant가 아니라 상태입니다. outline disabled, underlined disabled 모두 동일한 token 적용.
Common Behavior
- Border는 항상 표시합니다.
outlinevariant는 focus 여부와 무관하게stone-200border가 보여야 합니다. border 없이 focus glow만 사용하는 스타일(chat input, command palette 등)은 TextField가 아닌 별도 컴포넌트입니다. - Prefix icon은 필드의 종류를 빠르게 인지시키는 경우에만 사용합니다. 검색, 비밀번호, 이메일처럼 아이콘이 의미를 더할 때만 넣습니다.
- Clear suffix는 focus 여부가 아니라 값의 존재에 따라 표시합니다. 값이 없으면 숨기고, 값이 있으면 노출합니다.
- Focus 강조는 실제 focus일 때만 보여야 합니다. 검색창이라고 해서 항상 highlight된 상태로 두지 않습니다.
- 검색/커맨드 입력처럼 필드가 하나뿐인 경우
underlined를, 설정/로그인/다이얼로그 폼처럼 여러 필드가 있는 경우outline을 씁니다. - Prefix/Suffix 조합 규칙은 variant와 별개입니다.
outline + prefix,underlined + clear모두 조합 가능합니다.
Sizes
Default: md
| Size | Height | px | py | Text token | Use | Mobile (≥44pt hit area) |
|---|---|---|---|---|---|---|
sm | 32px | 10px | 6px | label1Regular 14/20 | Dense form, inline filter | 사용 안 함 (모바일은 md/lg만) |
md | 40px | 12px | 10px | label1Regular 14/20 | Default (web) | hitSlop 4pt 또는 lg로 승격 권장 |
lg | 48px | 16px | 12px | label1Regular 14/20 | Mobile primary (default) · 로그인 | ✓ 기본 충족 |
Radius: rounded-md (sm/md/lg).
왼쪽 아이콘 (Prefix)
입력 필드 왼쪽에 아이콘을 배치합니다. 필드의 목적을 시각적으로 보강할 때 사용합니다.
- 아이콘 색상:
stone-400(idle) · focus 시에도 유지 - 아이콘 색상:
stone-400(default) · focus 시에도 유지 - 아이콘 크기:
sm14px ·md16px ·lg18px - 좌측 padding을 아이콘이 대체 —
pl-3유지, 아이콘과 input 사이gap-2
오른쪽 아이콘 (Suffix)
입력 필드 오른쪽에 인터랙티브 아이콘을 배치합니다. Clear 버튼, 비밀번호 토글 등에 사용합니다.
- X (Clear) 버튼: 값이 있을 때만 표시 — 비어 있는 기본 상태에서는 숨김
- 비밀번호 토글: 항상 표시
- Suffix 아이콘은 모두 터치/클릭 가능한 버튼으로 구현 —
aria-label필수
양쪽 아이콘 (Prefix + Suffix)
검색 필드의 전형적인 조합입니다. 첫 줄은 비어 있는 기본 상태, 둘째 줄은 값이 들어온 상태입니다. Prefix는 항상 표시하고, Suffix(Clear)는 값이 있을 때만 표시합니다. focus ring은 실제 focus 시에만 추가합니다.
Sub-elements
Label
| Token | Value |
|---|---|
| Typography | label1Medium — 14px / 20 / Medium |
| Color | stone-700 |
| Color (invalid) | rose-600 |
| Required mark | * — rose-500 |
| Disabled | opacity 50% |
Label은 항상 Input 위에 위치합니다. Placeholder를 Label 대용으로 사용하지 않습니다.
HelperText
| Token | Value |
|---|---|
| Typography | caption1Regular — 12px / 16 / Regular |
| Color (default) | stone-400 |
| Color (invalid) | rose-600 |
| Spacing | mt-1.5 (6px) from Input |
HelperText와 ErrorText는 같은 위치를 차지합니다. invalid 상태가 되면 ErrorText가 HelperText를 대체합니다.
Token Mapping
| Token | outline | underlined |
|---|---|---|
| border (default) | 1px solid stone-200 (4면) | border-b 1px solid stone-200 |
| border (focus) | brown-800 (4면) | brown-800 (하단만) |
| ring (focus) | — | — |
| border (invalid) | rose-400 (4면) | rose-400 (하단만) |
| ring (invalid) | ring-2 ring-rose-500/10 | — |
| radius | rounded-md | rounded-none |
| background | white | transparent |
| padding | px-3 | px-0 |
| disabled bg | stone-50 | transparent |
공통 토큰:
| Token | Value |
|---|---|
| placeholder | stone-200 |
| text | brown-800 |
| disabled text | stone-400 |
| error text | rose-600 |
| input text | label1Regular |
| label | label1Medium · stone-700 |
| helper | caption1Regular · stone-400 |
| prefix/suffix icon | stone-400 |
Usage
// 기본
<TextField
label="Workspace Name"
placeholder="e.g. Q4 Planning"
helperText="팀 워크스페이스 이름을 입력하세요."
/>
// Required + Error
<TextField
label="이메일"
required
type="email"
invalid
errorText="올바른 이메일 형식이 아닙니다."
value={email}
onChange={setEmail}
/>
// Prefix 아이콘 (검색)
<TextField
placeholder="노트 검색..."
prefixIcon={<SearchIcon />}
value={query}
onChange={setQuery}
/>
// Suffix 아이콘 (Clear)
<TextField
label="검색"
prefixIcon={<SearchIcon />}
suffixIcon={query ? <ClearButton onClick={() => setQuery('')} /> : null}
value={query}
onChange={setQuery}
/>
// Suffix 아이콘 (비밀번호 토글)
<TextField
label="비밀번호"
type={show ? 'text' : 'password'}
prefixIcon={<LockIcon />}
suffixIcon={<EyeToggle onClick={() => setShow(!show)} />}
/>A11y
label의htmlFor와input의id를 반드시 연결합니다.- invalid 상태에서
aria-invalid="true"와aria-describedby로 ErrorText를 연결합니다. - required 필드는
*시각 표시 외aria-required="true"를 병행합니다. - disabled 상태에서 레이블도 같이 흐려야 하며, 이유를 tooltip 또는 HelperText로 안내합니다.
- Suffix 버튼(Clear, 비밀번호 토글 등)은 모두
aria-label필수. - Label 없이 prefix 아이콘만 있는 경우
aria-label또는 visually hidden Label 제공.
Do / Don't
- Do: 모든 입력 필드에 Label 제공
- Do: invalid는 border 색상 + ErrorText 문자로 이중 전달 (색맹 대응)
- Do: HelperText로 입력 형식 사전 안내 (예: "이름@회사.com 형식")
- Do: Clear(X) 버튼은 값이 있을 때만 표시
- Do: 화면에 입력 필드가 하나뿐이면
underlined사용 — 더 가볍고 집중적 - Don't:
outline필드에서 기본 border 제거 금지 — 필드 영역이 불명확해짐 (focus glow만 사용 금지) - Don't: placeholder를 label 대용으로 사용 — 포커스 시 사라져 맥락을 잃음
- Don't: Label과 HelperText를 동일 내용으로 중복 작성
- Don't: 같은 폼에서 크기를 혼용 (sm/lg 혼합 금지)
- Don't: 여러 필드가 있는 폼에
underlined혼용 금지 — 경계가 불명확해짐 - Don't: Suffix 버튼에
aria-label없이 아이콘만 배치 금지
