TextField#
사용자로부터 텍스트를 입력받는 컴포넌트입니다. 다양한 타입과 상태를 지원합니다.
Live Preview#
class TextFieldDefaultExample extends StatefulComponent {
const TextFieldDefaultExample({super.key});
@override
State<TextFieldDefaultExample> createState() =>
_TextFieldDefaultExampleState();
}
class _TextFieldDefaultExampleState extends State<TextFieldDefaultExample> {
@override
Component build(BuildContext context) {
return CoTextField(
placeholder: text('Enter text...'),
);
}
}
class TextFieldDefaultExample extends StatefulWidget {
const TextFieldDefaultExample({super.key});
@override
State<TextFieldDefaultExample> createState() =>
_TextFieldDefaultExampleState();
}
class _TextFieldDefaultExampleState extends State<TextFieldDefaultExample> {
@override
Widget build(BuildContext context) {
return CoTextField(
placeholder: const Text('Enter text...'),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 사용자로부터 짧은 텍스트를 입력받을 때 (이름, 이메일, 비밀번호 등)
- 검색 필드가 필요할 때
- 숫자, 전화번호 등 특정 형식의 입력이 필요할 때
대신 다른 컴포넌트를 사용하세요:
TextArea: 여러 줄의 긴 텍스트를 입력받을 때Select: 미리 정해진 옵션 중 선택할 때Autocomplete: 입력하면서 추천 목록에서 선택할 때DatePicker: 날짜를 입력받을 때
기본 사용법 (Basic Usage)#
// 기본 입력
CoTextField(
onChanged: handleNameChange,
placeholder: Text('이름을 입력하세요'),
)
// 비밀번호 입력
CoTextField(
obscureText: true,
placeholder: Text('비밀번호'),
)
// 라벨 및 에러
CoTextField(
label: '이메일',
onChanged: handleEmailChange,
errorText: '올바른 이메일을 입력하세요',
)
// 기본 입력
CoTextField(
onChanged: handleNameChange,
placeholder: text('이름을 입력하세요'),
)
// 비밀번호 입력
CoTextField(
obscureText: true,
placeholder: text('비밀번호'),
)
// 라벨 + 에러
CoTextField(
label: '이메일',
onChanged: handleEmailChange,
errorText: '올바른 이메일을 입력하세요',
)
스타일 시스템 — textFieldStyle (Epic #1302)#
CoTextField 의 chrome / dimensional / cursor / 슬롯 텍스트 미세 조정은 단일
textFieldStyle 필드(CoreTextFieldStyle) 하나로 흐릅니다.
CoTextArea
도 같은 CoreTextFieldStyle 을 공유 — chrome 99% 동일.
CoTextField(
variant: CoreTextFieldVariant.outline, // ← 시맨틱 enum 위젯 파라미터
size: CoreComponentSize.md, // ← 시맨틱 enum 위젯 파라미터
onChanged: handleEmailChange,
textFieldStyle: CoreTextFieldStyle( // ← chrome / 슬롯
borderRadius: 8,
paddingH: 16,
paddingV: 12,
focusBorderColor: cs.primary,
cursorColor: cs.primary,
valueStyle: CoreTextStyle(fontSize: 14), // ← 입력 텍스트
placeholderStyle: CoreTextStyle(color: cs.onSurfaceVariant),
leadingIconStyle: CoreIconStyle(size: 18),
),
leading: Icon(Icons.email),
label: '이메일',
)
CoreTextFieldStyle 의 22 필드:
-
chrome:
backgroundColor,borderColor,focusBorderColor,errorBorderColor,borderWidth,borderRadius -
dimensional:
height,minHeight,maxHeight,paddingH,paddingV,gap - cursor:
cursorColor,cursorWidth,cursorRadius -
nested slot:
labelStyle,placeholderStyle,valueStyle,descriptionStyle,errorStyle,leadingIconStyle,trailingIconStyle
Resolve chain#
design system default for variant
→ CoreTextFieldTheme.style // 프로젝트 공통
→ CoreTextFieldTheme.variantStyles[widget.variant] // variant 별
→ 부모 컴포넌트 슬롯 오버라이드
→ widget.textFieldStyle // 인스턴스별
nested slot styles 는 재귀 머지 — valueStyle.fontWeight 만 override 해도
valueStyle.fontSize / valueStyle.color 는 이전 레이어 값 유지.
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
placeholder |
Widget? / Component? |
null |
플레이스홀더 |
controller |
TextEditingController? |
null |
텍스트 컨트롤러 (Flutter) |
onChanged |
ValueChanged<String>? |
null |
값 변경 콜백 |
label | String? | null | 라벨 텍스트 |
description |
String? |
null |
설명 텍스트 |
errorText |
String? |
null |
에러 메시지 (설정 시 자동 error 스타일) |
enabled | bool | true | 활성화 여부 |
obscureText |
bool |
false |
비밀번호 마스킹 |
maxLines | int | 1 | 최대 줄 수 |
variant |
CoreTextFieldVariant |
defaultVariant |
시맨틱 변형 (위젯 파라미터) |
size |
CoreComponentSize |
md |
크기 토큰 (위젯 파라미터) |
textFieldStyle |
CoreTextFieldStyle? |
null |
chrome / dimensional / cursor / nested slot 묶음 |
prefix / suffix |
Widget? / Component? |
null |
입력 영역 좌/우 슬롯 |
controller / focusNode / statesController |
platform-specific | null |
외부 컨트롤러 |
변형 (Variants)#
variant는 errorText 파라미터로 자동 결정됩니다:
errorText가 null이면 → 기본 스타일errorText가 설정되면 → 에러 스타일 (빨간 보더)
// 기본 상태
CoTextField(
placeholder: Text('이름을 입력하세요'),
)
// 에러 상태 (errorText 설정 시 자동)
CoTextField(
errorText: '필수 입력 항목입니다',
placeholder: Text('이름을 입력하세요'),
)
// 비활성화
CoTextField(
enabled: false,
placeholder: Text('수정 불가'),
)
// 읽기 전용
CoTextField(
readOnly: true,
initialValue: '읽기 전용 값',
)
동작 스펙 (Behavior)#
포커스 관리#
- 클릭 또는 Tab 키로 포커스 획득 시 테두리 색상 변경
autofocus: true로 페이지 로드 시 자동 포커스
상태 전환#
-
default→focused(포커스 획득) →filled(값 입력) →default(포커스 해제) error:errorText설정 시 테두리와 에러 메시지 표시disabled: 모든 인터랙션 비활성화, 흐리게 표시readOnly: 포커스는 가능하나 편집 불가
사용 가이드라인 (Usage Guidelines)#
✅ Do#
항상 라벨과 함께 사용하세요.
CoTextField(
label: '이메일 주소',
placeholder: Text('user@example.com'),
)
라벨은 입력 필드의 용도를 명확히 하고, 접근성을 향상시킵니다.
❌ Don't#
placeholder만으로 라벨을 대체하지 마세요.
CoTextField(
placeholder: Text('이메일 주소'),
)
입력을 시작하면 placeholder가 사라져 필드 용도를 알 수 없게 됩니다.
✅ Do#
에러 메시지는 구체적으로 작성하세요.
CoTextField(
errorText: '이메일 형식이 올바르지 않습니다 (예: user@example.com)',
)
사용자가 무엇을 수정해야 하는지 바로 알 수 있습니다.
❌ Don't#
모호한 에러 메시지를 사용하지 마세요.
CoTextField(
errorText: '입력이 올바르지 않습니다',
)
사용자가 무엇을 고쳐야 하는지 알 수 없습니다.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
Tab | 다음 입력 필드로 이동 |
Shift+Tab | 이전 입력 필드로 이동 |
Enter | 폼 제출 (단일 라인) 또는 줄바꿈 (다중 라인) |
Escape | 포커스 해제 |
스크린 리더#
- Flutter:
Semantics로 라벨, 힌트, 에러 상태 자동 전달 - Web:
<input>요소의 네이티브 접근성.label속성으로 접근성 라벨 자동 연결
터치 타겟#
- 최소 터치 타겟 높이: 48dp
- 충분한 내부 패딩으로 터치 영역 확보