AutoComplete#
사용자 입력에 따라 일치하는 제안 목록을 실시간으로 표시하는 자동 완성 입력 컴포넌트입니다.
Live Preview#
Web
Flutter
Loading Flutter...
AutoComplete(
suggestions: ['Apple', 'Banana', 'Cherry'],
placeholder: 'Search fruits...',
onSelected: handleSelected,
)
AutoComplete(
suggestions: ['Apple', 'Banana', 'Cherry'],
placeholder: 'Search fruits...',
onSelected: handleSelected,
)
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 사전에 알려진 값 목록에서 선택해야 하는 경우 (국가, 도시, 사용자 이름 등)
- 검색 입력에서 실시간 제안을 제공해야 하는 경우
- API로부터 동적으로 제안을 가져와야 하는 경우
- 자유 입력도 허용하면서 제안도 함께 제공해야 하는 경우
대신 다른 컴포넌트를 사용하세요:
Select: 선택지가 고정되어 있고 자유 입력이 필요 없는 경우ChipInput: 여러 항목을 태그 형태로 선택해야 하는 경우Input: 제안 없이 순수한 텍스트 입력만 필요한 경우
기본 사용법 (Basic Usage)#
// 기본 자동 완성
AutoComplete(
suggestions: ['Apple', 'Banana', 'Cherry', 'Grape'],
onSelected: handleFruitSelected,
labelText: '과일 검색',
)
// 비동기 검색
AutoComplete(
asyncSearch: (query) async {
final results = await searchApi.search(query);
return results.map((r) => r.name).toList();
},
onSelected: handleResultSelected,
debounceMs: 300,
labelText: '검색어 입력',
)
// 커스텀 필터
AutoComplete(
suggestions: cityList,
filter: (item, query) => item.toLowerCase().startsWith(query.toLowerCase()),
onSelected: handleCitySelected,
labelText: '도시 선택',
)
// 기본 자동 완성
AutoComplete(
suggestions: ['Apple', 'Banana', 'Cherry', 'Grape'],
onSelected: handleFruitSelected,
placeholder: '과일 검색',
)
// 비동기 작동 — onChanged로 입력마다 외부 검색 트리거
AutoComplete(
suggestions: searchResults, // 외부에서 업데이트되는 목록
onChanged: handleQueryChanged, // 입력 시 API 호출 후 suggestions 갱신
onSelected: handleResultSelected,
placeholder: '검색어 입력',
)
// 커스텀 필터링 — 시작 문자 일치 필터 예시
AutoComplete(
suggestions: cityList,
onSelected: handleCitySelected,
placeholder: '도시 선택',
// Web은 브라우저 datalist 기반 — 커스텀 필터는 suggestions를 외부에서 가공
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
suggestions |
List<String>? |
null |
정적 제안 목록 |
onSelected |
ValueChanged<String>? |
null |
항목 선택 콜백 |
labelText |
String? |
null |
입력 필드 라벨 |
filter |
bool Function(String item, String query)? |
null |
커스텀 필터 함수 |
asyncSearch |
Future<List<String>> Function(String query)? |
null |
비동기 검색 함수 |
debounceMs |
int |
300 |
비동기 검색 딜레이 (밀리초) |
maxSuggestions |
int |
5 |
최대 표시 제안 수 |
onChanged |
ValueChanged<String>? |
null |
입력 값 변경 콜백 |
변형 (Variants)#
정적 목록#
AutoComplete(
suggestions: countries,
onSelected: handleCountrySelected,
labelText: '국가 선택',
maxSuggestions: 8,
)
비동기 검색#
AutoComplete(
asyncSearch: (query) => userRepository.searchUsers(query),
onSelected: handleUserSelected,
debounceMs: 500,
labelText: '사용자 검색',
)
동작 스펙 (Behavior)#
인터랙션#
- 입력: 사용자가 타이핑하면 필터링된 제안 목록이 드롭다운으로 표시됨
- 선택: 제안 항목 클릭 또는 키보드 방향키 + Enter로 선택
- 닫기: 외부 클릭, Escape 키, 또는 항목 선택 시 드롭다운 닫힘
- 호버: 제안 항목에 마우스 오버 시 시각적 하이라이트 표시
상태 전환#
idle→focused(입력 필드 포커스 시)focused+ 입력 →suggesting(제안 목록 표시)suggesting→selected(항목 선택 시)suggesting→idle(Escape 또는 외부 클릭 시)disabled상태에서는 모든 인터랙션 무시
디바운스#
- 비동기 검색(
asyncSearch) 사용 시 기본 300ms 디바운스 적용 - 연속 입력 중 불필요한 API 호출 방지
debounceMs: 0으로 즉시 검색 가능
사용 가이드라인 (Usage Guidelines)#
✅ Do#
비동기 검색에 적절한 디바운스 설정
CouiAutoComplete(
asyncSearch: (query) => productApi.search(query),
onSelected: handleProductSelected,
debounceMs: 300, // API 호출 빈도 조절
labelText: '상품 검색',
)
불필요한 API 요청을 방지하고 서버 부하를 줄인다.
❌ Don't#
디바운스 없이 매 입력마다 API 호출
// ❌ debounceMs: 0으로 설정하면 모든 키 입력마다 API 호출
CouiAutoComplete(
asyncSearch: (query) => productApi.search(query),
onSelected: handleProductSelected,
debounceMs: 0,
)
과도한 API 호출로 서버 부하가 발생하고 UX가 저하된다.
✅ Do#
최대 제안 수를 적절히 제한
CouiAutoComplete(
suggestions: allCountries, // 200여 개 국가
onSelected: handleCountrySelected,
maxSuggestions: 8, // 화면에 적절한 수만 표시
labelText: '국가 선택',
)
너무 많은 제안은 스크롤이 필요해 사용성이 떨어진다.
❌ Don't#
검색 결과 없음 피드백 생략
// ❌ 빈 목록만 보여주면 사용자가 혼란스러움
CouiAutoComplete(
suggestions: [], // 아무것도 없을 때 빈 드롭다운 표시
onSelected: handleSelected,
)
검색 결과가 없을 때 명확한 안내 메시지를 제공해야 사용자 경험이 향상된다.
✅ Do#
선택지가 고정된 경우 Select를 대신 사용하세요.
// ✅ 고정된 5개 옵션이라면 Select가 더 적합
CouiSelect(
options: ['서울', '부산', '대전', '대구', '광주'],
onChanged: handleCityChanged,
label: '도시 선택',
)
AutoComplete는 목록이 길거나 동적으로 변하는 경우에 적합합니다. 고정 옵션이 소수라면 Select가 더 명확합니다.
❌ Don't#
빈 쿼리에도 전체 목록을 노출하지 마세요.
// ❌ 포커스만 해도 전체 200개 국가 표시
CouiAutoComplete(
suggestions: allCountries, // 200개
onSelected: handleCountrySelected,
showSuggestionsOnEmpty: true, // 빈 입력에도 전체 표시
)
빈 쿼리에 전체 목록을 보여주면 사용자가 압도될 수 있습니다. 최소 1~2자 입력 후 제안을 표시하세요.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
↓ / ↑ | 제안 목록 항목 탐색 |
Enter | 선택된 제안 항목 확정 |
Escape | 제안 목록 닫기 |
Tab | 다음 포커스 가능 요소로 이동 (목록 닫힘) |
스크린 리더#
-
Flutter:
Semantics위젯으로comboboxrole과 제안 목록 상태(expanded/collapsed) 전달 -
Web:
role="combobox",aria-autocomplete="list",aria-expanded자동 적용
터치 타겟#
- 최소 터치 타겟 크기: 48x48dp
- 제안 항목 높이: 최소 44dp로 터치 오동작 방지
크로스 플랫폼 차이점 (Platform Differences)#
v3.0부터 기본 API (
enabled,onChanged,value등)가 통일되었습니다. 아래는 플랫폼 고유 차이점만 나열합니다.
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CouiAutoComplete | AutoComplete |
| 라벨 속성 | labelText | label |
| 드롭다운 위치 | 입력 필드 아래 오버레이 | position: absolute CSS |
| 필터 방식 | Dart 함수 | JavaScript 함수 |
관련 컴포넌트 (Related Components)#
- Input: 자동 완성 없이 단순 텍스트 입력이 필요한 경우
- Select: 고정된 옵션 목록에서만 선택해야 하는 경우
- ChipInput: 자동 완성과 함께 여러 항목을 태그로 추가해야 하는 경우
조합 예제#
// AutoComplete + Form 조합: 사용자 검색 후 선택
CouiForm(
child: Column(
children: [
CouiAutoComplete(
asyncSearch: (query) => userRepository.searchUsers(query),
onSelected: handleUserSelected,
labelText: '담당자 검색',
debounceMs: 300,
),
CouiInput(
label: '이메일',
onChanged: handleEmailChanged,
),
],
),
)