Input
Stable사용자가 텍스트를 입력하고 수정할 수 있는 필드입니다.
Overview
Input은 이름, 이메일, 검색어처럼 사용자가 직접 텍스트를 입력할 때 사용합니다. 레이블·도움말·오류 메시지를 함께 제공해 필요한 값과 현재 상태를 명확하게 안내합니다.
현재 값: 없음
<Field label="이름" size="md" invalid={false}
description="예약에 사용할 이름을 입력하세요."
errorMessage="입력한 값을 확인해 주세요."
>
<Input placeholder="이름을 입력하세요" />
</Field>placeholder는 입력 예시일 뿐입니다. 사용자가 값을 입력해도 사라지지 않는 독립된 label을 항상 함께 제공해야 합니다.
Anatomy
| 번호 | 구성 요소 | 역할 |
|---|---|---|
| 1 | Label | 필드 이름. htmlFor와 id로 자동 연결 |
| 2 | Container | 크기·경계 테두리·배경 및 포커스 링 영역 |
| 3 | Value / Placeholder | 사용자 입력 값 또는 입력 힌트 안내 문구 |
| 4 | Start / End Icon | 입력 목적을 시각적으로 보조하는 장식용 아이콘 (aria-hidden) |
| 5 | Description / Error | aria-describedby로 연결되는 도움말 또는 유효성 오류 메시지 |
번호는 구성 요소를 식별하며 배치 순서를 고정하지 않습니다. startIcon과 endIcon으로 아이콘을 입력 영역 앞이나 뒤에 둘 수 있습니다. 조작 버튼은 장식용 아이콘 슬롯 대신 Field의 suffix를 사용하세요.
Variants
별도의 복잡한 시각적 변형 대신 아이콘 슬롯과 HTML5 네이티브 type을 조합하여 다양한 입력 목적을 지원합니다.
| Variant | 미리보기 (Preview) | 특징 및 사용 예시 |
|---|---|---|
| 기본 텍스트 | 가장 표준적인 일반 텍스트 입력 필드 | |
| 아이콘 포함 | startIcon 또는 endIcon으로 검색이나 필터링 목적을 시각적으로 표현 | |
| 이메일 / 특수 타입 | 모바일 가상 키보드 최적화(@, .com) 및 브라우저 자동완성 지원 |
Sizes
공통 Control size 네 단계를 사용합니다. 기본 md는 40px이며, 모바일의 주요 입력에는 lg(48px)를 권장합니다.
| Size | 높이 (Height) | 미리보기 (Preview) | 패딩 & 폰트 크기 |
|---|---|---|---|
sm | … | 패딩: … · 폰트: … | |
md | … | 패딩: … · 폰트: … | |
lg | … | 패딩: … · 폰트: … | |
xl | … | 패딩: … · 폰트: … |
States
Default, Error, ReadOnly, Disabled 상태를 지원하며, 시각적 테두리와 접근성 속성으로 명확히 구분합니다.
| 상태 (State) | 미리보기 (Preview) | 동작 및 가이드 |
|---|---|---|
| Default | 사용자 입력을 대기하는 기본 활성 인터랙션 상태 | |
| Error | 유효성 검증 실패 시 강조 테두리(Red)와 aria-invalid 적용 | |
| ReadOnly | 값 수정은 차단되지만 텍스트 선택 및 클립보드 복사는 허용 | |
| Disabled | 조작 및 폼 전송에서 완전히 제외되는 비활성화 상태 |
Input 상태 토큰 전체
| Token | 정의 / 매핑 | 현재 값 |
|---|---|---|
--guide-input-default-bg | var(--guide-bg-base) | … |
--guide-input-default-border | var(--guide-line-default) | … |
--guide-input-default-text | var(--guide-text-primary) | … |
--guide-input-default-icon | var(--guide-icon-default-color) | … |
--guide-input-focus-border | var(--guide-line-focus) | … |
--guide-input-focus-text | var(--guide-text-primary) | … |
--guide-input-focus-icon | var(--guide-icon-strong-color) | … |
--guide-input-error-border | var(--guide-line-error) | … |
--guide-input-error-text | var(--guide-text-error) | … |
--guide-input-readonly-bg | var(--guide-bg-surface-light) | … |
--guide-input-readonly-border | var(--guide-line-default) | … |
--guide-input-readonly-text | var(--guide-text-primary) | … |
--guide-input-readonly-icon | var(--guide-icon-muted-color) | … |
--guide-input-disabled-bg | var(--guide-bg-disabled) | … |
--guide-input-disabled-border | var(--guide-line-default) | … |
--guide-input-disabled-text | var(--guide-text-on-disabled) | … |
--guide-input-disabled-icon | var(--guide-icon-muted-color) | … |
Guidelines
권장해요
항상 보이는 레이블과 구체적인 도움말을 제공합니다.
오류에는 aria-invalid와 수정 방법을 설명하는 메시지를 함께 제공합니다.
입력 목적에 맞는 type, autoComplete, inputMode를 사용합니다.
피해주세요
placeholder만으로 레이블을 대신하지 않습니다.
값을 읽기만 해야 할 때 disabled로 정보를 숨기지 않고 readOnly를 고려합니다.
여러 줄 입력이 필요한 영역에는 Input 대신 Textarea를 사용합니다.
API
| Prop | Type | Default | Description |
|---|---|---|---|
| size | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 컨트롤의 높이와 패딩 크기 스케일 |
| type | HTMLInputTypeAttribute | 'text' | HTML5 입력 유형 (text, email, search 등) |
| startIcon | ReactNode | undefined | 텍스트 좌측에 위치하는 장식용 아이콘 (aria-hidden) |
| endIcon | ReactNode | undefined | 텍스트 우측에 위치하는 장식용 아이콘 |
| disabled | boolean | false | 조작 불가 및 폼 전송 제외 여부 |
| readOnly | boolean | false | 값 수정 불가 및 텍스트 선택/복사 허용 여부 |
| aria-invalid | boolean | "true" | "false" | undefined | 오류 상태 테두리 강조 표시 |
| aria-describedby | string | undefined | 도움말 또는 오류 메시지 요소의 id 연결 |
| wrapperClassName | string | '' | 외부 컨테이너 커스텀 스타일 클래스 |
| className | string | '' | 내부 input 요소 커스텀 스타일 클래스 |
| …native props | ComponentProps<"input"> | — | value, onChange, placeholder, name, required, maxLength 등 |
Code Example
'use client';
import { useState } from 'react';
import { Field, Input } from '@/components/ui';
export default function Example() {
const [email, setEmail] = useState('');
return (
<Field
label="이메일"
required
description="알림을 수신할 이메일 주소를 입력해 주세요."
>
<Input
type="email"
name="email"
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="user@example.com"
/>
</Field>
);
}