ComponentsP3 본문

Autocomplete

비동기 태그 입력 콤보박스 — 자유 텍스트로 검색하고 외부 주입 suggestions에서 골라 칩으로 쌓습니다. 서버 조회는 소비자가 onQueryChange로 수행하는 비제어 컴포넌트입니다.

마지막 업데이트 2026-06-11

한눈에#

비동기 태그 입력 콤보박스 — 자유 텍스트로 검색하고 외부 주입 suggestions에서 골라 칩으로 쌓습니다. 서버 조회는 소비자가 onQueryChange로 수행합니다.

아직 선택 없음

  • 비동기 태그
  • 칩 누적
  • onQueryChange
  • maxSelections

입력하면 후보가 열리고 선택하면 칩으로 쌓입니다

사용 시점#

서버 제안에서 골라 칩으로 쌓으면 Autocomplete — 그 외에는 목적에 맞는 컴포넌트를 가리킵니다.

권장 — 이렇게 쓰세요

지양 — 이러지 마세요

아직 선택 없음

쓴다자유 텍스트 검색 + 서버 제안에서 골라 칩으로 누적(태그 입력)

대신 SearchField값 선택이 아니라 검색 실행(Enter로 결과 이동)

대신 Select고정 옵션 단일 선택

대신 MultiSelect고정 옵션 다중 선택

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

Autocomplete를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

변형#

아직 선택 없음

maxSelections — 상한 도달 시 입력이 비활성되고 안내가 표시됩니다 (칩 제거로 해제)

defaultValue로 초기 칩을 채울 수 있고, suggestions에 없는 값은 value 문자열이 그대로 칩 라벨이 됩니다. 이미 선택된 항목은 목록에서 제외됩니다.

크기#

단일 크기입니다 — 트리거 최소 높이는 input.height(44px)로 Input과 같은 폼 컨트롤 줄맞춤이고, 칩이 늘어나면 줄바꿈하며 세로로 자랍니다. 최소 폭은 16rem(MultiSelect와 동일), 팝업 리스트는 최대 16rem 높이에서 스크롤됩니다.

상태#

  • Focus — 포커스 링은 wrap :focus-withininput.border-focus 보더 + 18% 링 (Input과 동일)
  • Loadingloading이면 목록 대신 스피너 행(role="status", ‘로딩 중’)
  • Empty — 남은 후보가 없으면 emptyText(‘결과 없음’) 행
  • Max 도달 — 입력 disabled + 안내 문구(role="status", aria-describedby 연결)
  • Disabledinput.bg-disabled 배경, 칩 제거 버튼도 함께 숨김

비제어 컴포넌트입니다 — defaultValue로 시작하고 칩 추가/제거 시 onChange(values)로 알립니다.

Props#

Prop타입기본값설명
suggestionsreadonly AutocompleteSuggestion[]외부 주입 후보 — 서버 조회 결과는 소비자가 onQueryChange로 갱신해 되돌린다
defaultValuereadonly string[]초기 선택 value 배열 — 이후 상태는 내부 소유(비제어)
onChange(values: string[]) => void칩 추가/제거 시 선택 value 배열 콜백
onQueryChange(query: string) => void입력 쿼리 변경 콜백 — 서버 조회 트리거 지점
loadingbooleanfalse목록 대신 로딩 표시
maxSelectionsnumber선택 상한 — 도달 시 입력 비활성 + 안내 표시
maxSelectionsTextstring상한 도달 안내 문구 — 기본 '최대 N개까지 선택할 수 있습니다'
emptyTextstring결과 없음남은 후보가 없을 때 표시 문구
refRef<HTMLInputElement>검색 텍스트 <input> 요소로 병합 전달되는 ref (React 19 ref-as-prop)

접근성#

입력이 role="combobox" + aria-autocomplete="list" + aria-haspopup="listbox", 팝업이 role="listbox"입니다. 포커스는 항상 입력에 머물고 aria-activedescendant가 활성 옵션 id를 가리킵니다. 칩 제거 버튼은 aria-label="{label} 제거"로 이름이 붙고 44px 히트 영역을 가집니다.

동작
문자 입력목록 열기 + onQueryChange 발화
(닫힘)목록 열기 — 첫 옵션 활성
/ (열림)활성 옵션 이동 — 양 끝에서 클램프
Enter활성 옵션 선택 → 칩 추가 + 쿼리 비움 + 닫기
Escape선택 없이 닫기
Backspace (빈 입력)마지막 칩 제거

외부 클릭으로도 닫히며, 상한 도달 안내는 role="status" + aria-describedby로 입력과 연결됩니다.

토큰#

component 토큰 없이 Input의 component 토큰(input.*)과 semantic을 직접 소비합니다(신설 기준 §4 미충족).

속성토큰
트리거input.bg/fg/border/height/radius · placeholder input.placeholder
포커스input.border-focus + color.primary 18% 링 (:focus-within)
Tag(neutral sm) — color.surface-muted · color.text-muted · radius.full
팝업color.surface-raised · radius.md · shadow.lg · z.dropdown
옵션 활성color.surface-hover · 눌림 color.surface-pressed · 설명 잉크 color.text-subtle
옵션 높이control.height-sm
안내/빈 상태color.text-subtle · color.text-muted
비활성input.bg-disabled
모션duration.fast + ease.out/standard