ChipInput#
텍스트를 입력하고 Enter로 확인하면 칩(태그) 형태로 추가되는 다중 항목 입력 컴포넌트입니다.
Live Preview#
Web
Flutter
Loading Flutter...
ChipInput(
chips: ['Flutter', 'Dart'],
placeholder: 'Add tags...',
onChanged: handleChipsChanged,
)
ChipInput.simple(
chips: ['Flutter', 'Dart'],
placeholder: 'Add tags...',
onChanged: handleChipsChanged,
)
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 태그, 이메일 주소, 키워드 등 여러 항목을 동적으로 추가/제거해야 하는 경우
- 선택 개수가 가변적인 다중 입력이 필요한 경우
- 입력한 값을 시각적으로 태그 형태로 확인하면서 관리해야 하는 경우
대신 다른 컴포넌트를 사용하세요:
AutoComplete: 미리 정의된 목록에서 항목을 검색해 선택해야 하는 경우Chip: 미리 정의된 칩 목록에서 토글 선택하는 경우Select: 고정된 옵션 목록에서 다중 선택이 필요한 경우
기본 사용법 (Basic Usage)#
// 기본 칩 입력 (제네릭, chipBuilder 필수)
ChipInput<String>(
chips: selectedTags,
chipBuilder: (context, chip) => Text(chip),
onChanged: handleTagsChanged,
placeholder: Text('태그 입력 후 Enter'),
)
// 자동완성 제안 목록과 함께 사용
ChipInput<String>(
chips: selectedSkills,
chipBuilder: (context, chip) => Text(chip),
suggestions: availableSkills,
onChanged: handleSkillsChanged,
onSuggestionChoosen: handleSuggestionChoosen,
placeholder: Text('스킬 추가'),
)
// 컨트롤러 기반 상태 관리
ControlledChipInput<String>(
chips: emailList,
chipBuilder: (context, chip) => Text(chip),
onChanged: handleEmailListChanged,
placeholder: Text('이메일 추가'),
)
// 기본 칩 입력 (String 기반, 단순 API)
ChipInput(
chips: selectedTags,
onChanged: handleTagsChanged,
placeholder: '태그 입력 후 Enter',
)
// 최대 개수 제한
ChipInput(
chips: selectedSkills,
onChanged: handleSkillsChanged,
placeholder: '스킬 추가',
maxChips: 5,
)
// 비활성화 상태
ChipInput(
chips: emailList,
onChanged: handleEmailListChanged,
placeholder: '이메일 추가',
enabled: false,
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
values | List<String> | 필수 | 현재 칩 목록 |
onChanged |
ValueChanged<List<String>>? |
null |
목록 변경 콜백 |
onAdd |
ValueChanged<String>? |
null |
칩 추가 콜백 |
onRemove |
ValueChanged<String>? |
null |
칩 제거 콜백 |
placeholder |
String? |
null |
입력 필드 플레이스홀더 |
maxChips | int? | null | 최대 칩 수 |
validator |
String? Function(String)? |
null |
입력 유효성 검사 함수 |
변형 (Variants)#
태그 입력#
ChipInput(
values: articleTags,
onChanged: handleArticleTagsChanged,
placeholder: '태그를 입력하세요',
maxChips: 10,
)
이메일 수신자#
ChipInput(
values: recipients,
onChanged: handleRecipientsChanged,
placeholder: '이메일 주소 추가',
validator: validateEmail,
)
동작 스펙 (Behavior)#
인터랙션#
- 추가: 텍스트 입력 후
Enter키 또는,구분자로 칩 추가 - 제거: 칩 내
×버튼 클릭 또는 Backspace로 마지막 칩 제거 - 편집 불가: 추가된 칩의 텍스트는 직접 수정 불가 (제거 후 재입력)
- maxChips 도달: 최대 개수 도달 시 입력 필드 비활성화
상태 전환#
empty→typing(입력 필드 포커스 및 타이핑)typing→chip-added(Enter 또는,입력 시 칩 생성)chip-added→typing(계속 입력 가능)invalid상태: validator 실패 시 입력 필드에 에러 표시 (칩 생성 차단)max-reached: maxChips 도달 시 입력 필드disabled처리
중복 처리#
- 동일한 값의 칩은 기본적으로 추가되지 않음
- 대소문자 구분 없이 중복 검사
사용 가이드라인 (Usage Guidelines)#
✅ Do#
validator로 입력 형식을 검증
CouiChipInput(
values: emailRecipients,
onChanged: handleRecipientsChanged,
placeholder: '수신자 이메일 추가',
validator: (value) {
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) return '유효한 이메일 주소를 입력하세요';
return null;
},
)
잘못된 형식의 값이 칩으로 추가되기 전에 검증하여 데이터 품질을 보장한다.
❌ Don't#
자동완성과 함께 미리 정해진 목록에서만 선택하는 경우에 사용
// ❌ 고정 목록에서 선택만 필요하다면 AutoComplete나 Select 사용
CouiChipInput(
values: selectedCategories,
onChanged: handleCategoriesChanged,
// 자유 입력이 가능하여 유효하지 않은 카테고리가 추가될 수 있음
)
미리 정의된 옵션만 허용해야 한다면 AutoComplete나 Select를 사용하고 ChipInput은 자유 입력이 허용될 때 사용한다.
✅ Do#
maxChips와 함께 남은 입력 가능 수 안내
CouiChipInput(
values: selectedSkills,
onChanged: handleSkillsChanged,
placeholder: '스킬 추가 (최대 5개)',
maxChips: 5,
)
최대 개수를 명시하면 사용자가 미리 입력 계획을 세울 수 있다.
❌ Don't#
maxChips 없이 무제한 칩 추가 허용
// ❌ 제한 없이 너무 많은 칩이 추가되면 레이아웃이 깨질 수 있음
CouiChipInput(
values: tags,
onChanged: handleTagsChanged,
placeholder: '태그 추가',
// maxChips 미설정 - 수십 개 이상 추가 가능
)
서비스 요구사항에 맞는 적절한 최대 개수를 설정하여 UI 일관성을 유지한다.
✅ Do#
이미 추가된 항목은 중복 추가를 방지하세요.
CouiChipInput(
allowDuplicate: false, // 중복 입력 방지
suggestions: allTags,
onChanged: handleTagsChanged,
label: '태그 추가',
)
중복 태그가 추가되면 데이터 정합성이 깨지고 사용자가 혼란을 겪습니다. 기본적으로 중복을 방지하세요.
❌ Don't#
최대 개수 제한 없이 무한 추가를 허용하지 마세요.
// ❌ maxChips 미설정으로 무한 추가 허용
CouiChipInput(
suggestions: allItems,
onChanged: handleItemsChanged,
// maxChips 없음
)
제한 없이 항목을 추가할 수 있으면 UI가 넘치고 성능 문제가 발생할 수 있습니다. maxChips로 상한을 설정하세요.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
Enter | 현재 입력 텍스트를 칩으로 추가 |
, | 현재 입력 텍스트를 칩으로 추가 (구분자) |
Backspace | 입력 필드가 비어 있을 때 마지막 칩 제거 |
Delete | 포커스된 칩 제거 |
← / → | 칩 간 포커스 이동 |
Tab | 다음 포커스 가능 요소로 이동 |
스크린 리더#
- Flutter:
Semantics로 각 칩에 값 + "삭제 버튼" 레이블 제공 -
Web: 각 칩에
role="option",aria-selected="true", 삭제 버튼에aria-label="[값] 삭제"자동 적용
터치 타겟#
- 칩 삭제 버튼 최소 크기: 32x32dp (칩 내 여백 포함 44dp)
- 입력 필드 최소 높이: 48dp
크로스 플랫폼 차이점 (Platform Differences)#
v3.0부터 기본 API (
enabled,onChanged등)가 통일되었습니다. 아래는 플랫폼 고유 차이점만 나열합니다.
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CouiChipInput | ChipInput |
| 칩 스타일 | CouiChip 위젯 | CSS 스타일 태그 |
관련 컴포넌트 (Related Components)#
- Chip: 미리 정의된 칩 목록에서 선택/해제하는 경우
- Input: 단일 텍스트 값만 입력받는 경우
- AutoComplete: 입력 시 제안 목록과 함께 단일 항목을 선택하는 경우
조합 예제#
// ChipInput + AutoComplete 조합: 추천 태그와 함께 자유 입력
Column(
children: [
// 추천 태그를 자동완성으로 제공하면서 자유 입력도 허용
CouiAutoComplete(
suggestions: popularTags,
onSelected: (tag) {
handleTagsChanged([...currentTags, tag]);
},
labelText: '추천 태그 검색',
),
CouiChipInput(
values: currentTags,
onChanged: handleTagsChanged,
placeholder: '직접 태그 입력',
maxChips: 10,
),
],
)