Components · 폼
Input (텍스트 필드)
라벨·필드·헬프텍스트로 이뤄진 한 줄/여러 줄 텍스트 입력 컨트롤. 오류는 필드 바로 아래 인라인 텍스트로 알린다.
정의
사용자가 텍스트를 직접 입력하는 폼 컨트롤 컴포넌트다.
Anatomy
| 부위 | 토큰 |
|---|---|
| ① 라벨 | 글자 --input-fg · --text-label · 필수 별표 색 --color-state-danger-solid |
| ② 입력 필드 | bg --input-bg · 보더 --input-border(1px) · 모서리 --input-radius · 패딩 --input-pad-y/--input-pad-x · 글자 --text-body · placeholder --input-placeholder |
| ③ 헬프텍스트 | 안내 --color-text-muted · 오류 시 --color-state-danger-fg · 크기 --text-caption |
변형
| 변형 | 용도 |
|---|---|
| 단일 줄(기본) | 짧은 한 줄 값 — 이름·연락처·기관명 |
| 여러 줄(Textarea) | 문의 내용·요청사항 등 여러 줄 입력 |
상태
| 상태 | 값 |
|---|---|
| Default | border --input-border |
| Focus | border --input-border-focus + box-shadow: var(--focus-ring) |
| Disabled | opacity: var(--opacity-disabled) + cursor: not-allowed |
| Error | border --color-state-danger-solid + 헬프텍스트 --color-state-danger-fg |
Do / Don't
Do
- 라벨은 항상 필드 위에 보이게 둔다 — 입력을 시작해도 맥락이 사라지지 않는다.
- 오류는 필드 바로 아래 인라인 텍스트로, 무엇을 어떻게 고칠지 함께 알린다.
- placeholder에는 형식을 보여주는 예시값을 넣는다("예: 02-000-0000").
Don't
- placeholder를 라벨 대용으로 쓰지 말 것 — 입력을 시작하면 사라져 무엇을 넣는 칸인지 알 수 없다.
- 오류를 빨간 보더(색)만으로 표시하지 말 것 — 원인·해결 텍스트를 함께 둔다.
- placeholder를 "이름을 입력하세요" 같은 명령형 안내로 채우지 말 것 — 라벨이 할 일이다.
콘텐츠 규칙
- 라벨은 명사형으로 짧게("담당자 이름", "연락처") — 문장·명령형 금지.
- placeholder는 예시값("예: 홍길동", "예: 서울시 ○○구")으로, 라벨을 대체하지 않는다.
- 헬프텍스트는 1문장, 오류 메시지는 원인 + 해결을 담는다("숫자만 입력하세요").
- 조사 오류·띄어쓰기는 발행 전 점검(전역 규칙:
../guidelines/ux-writing.md).
키보드 인터랙션
| 키 | 동작 |
|---|---|
Tab / Shift+Tab | 다음/이전 필드로 포커스 이동(포커스 링 표시) |
| 문자·숫자 키 | 값 입력 |
Enter | 폼 안에서 제출(단일 줄) |
접근성
- 라벨은
<label for>로 필드와 연결한다 — placeholder는 라벨이 아니다. - 포커스는 보더 색만으로 끝내지 말고 포커스 링(
--focus-ring)을 함께 — 저시력 대비. - 오류는
aria-invalid="true"+ 헬프텍스트를aria-describedby로 연결해 스크린리더가 함께 읽게 한다. - 필수는
required+ 시각 별표, 히트영역은 패딩으로--target-min확보. 기준:../guidelines/accessibility.md.
코드
안전표지 견적서를 받을 담당자 성함입니다.
숫자만 입력하세요.
html
<div class="pi-field">
<label class="pi-field__label" for="contact-name">담당자 이름</label>
<input class="pi-input" id="contact-name" type="text" placeholder="예: 홍길동"
aria-describedby="contact-name-help">
<p class="pi-field__help" id="contact-name-help">안전표지 견적서를 받을 담당자 성함입니다.</p>
</div>
<div class="pi-field">
<label class="pi-field__label" for="contact-tel">연락처</label>
<input class="pi-input" id="contact-tel" type="tel" placeholder="예: 02-000-0000"
aria-invalid="true" aria-describedby="contact-tel-help">
<p class="pi-field__help pi-field__help--error" id="contact-tel-help">숫자만 입력하세요.</p>
</div>
<div class="pi-field">
<label class="pi-field__label" for="contact-memo">요청 내용</label>
<textarea class="pi-input pi-input--area" id="contact-memo" rows="3"
placeholder="예: 어린이보호구역 노면표시 시공을 문의합니다."></textarea>
</div>css
.pi-field { display: flex; flex-direction: column; gap: var(--space-2); word-break: keep-all; }
.pi-field__label {
font: var(--text-label);
letter-spacing: var(--text-label-letter-spacing);
color: var(--input-fg);
}
.pi-input {
background: var(--input-bg);
border: var(--border-thin) solid var(--input-border);
border-radius: var(--input-radius);
padding: var(--input-pad-y) var(--input-pad-x);
font: var(--text-body);
letter-spacing: var(--text-body-letter-spacing);
color: var(--input-fg);
min-height: var(--target-min);
transition: border-color var(--duration-base) var(--easing-out),
box-shadow var(--duration-base) var(--easing-out);
}
.pi-input::placeholder { color: var(--input-placeholder); }
.pi-input:focus-visible {
outline: none;
border-color: var(--input-border-focus);
box-shadow: var(--focus-ring);
}
.pi-input:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }
.pi-input[aria-invalid="true"] { border-color: var(--color-state-danger-solid); }
.pi-input--area { min-height: auto; resize: vertical; line-height: var(--font-lh-relaxed); }
.pi-field__help { margin: 0; font: var(--text-caption); color: var(--color-text-muted); }
.pi-field__help--error { color: var(--color-state-danger-fg); }
@media (prefers-reduced-motion: reduce) {
.pi-input { transition: none; }
}Changelog
| 날짜 | 변경 |
|---|---|
| 2026-07-15 | 문서 계약(10섹션) 적용 — Anatomy 도해·상태 매트릭스·오류 인라인 텍스트·콘텐츠 규칙·코드 신설, 기존 규격 승계 |