ComponentsP3 본문

Autocomplete

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

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

한눈에#

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

아직 선택 없음

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

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

사용 시점#

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

쓴다

아직 선택 없음

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

대신 SearchField

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

대신 Select

고정 옵션 단일 선택

대신 MultiSelect

고정 옵션 다중 선택

플레이그라운드#

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

import { Autocomplete } from '@wds/ui-web';

<Autocomplete
  aria-label="기술 스택"
  suggestions={[
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue' },
    { value: 'svelte', label: 'Svelte' },
    { value: 'angular', label: 'Angular' },
  ]}
/>

변형#

아직 선택 없음

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타입기본값설명
suggestionsReadonlyArray<AutocompleteSuggestion>{ value, label, description? } 후보 배열 — 서버 조회 결과를 외부에서 주입
defaultValueReadonlyArray<string>초기 선택 value 배열 — 이후 상태는 내부 소유(비제어)
onChange(values: string[]) => void칩 추가/제거 시 선택 value 배열 콜백
onQueryChange(query: string) => void입력 쿼리 변경 콜백 — 서버 조회 트리거 지점 (선택 확정 시 빈 문자열로 재호출)
loadingbooleanfalse목록 대신 스피너 표시
maxSelectionsnumber선택 상한 — 도달 시 입력 비활성 + 안내 표시
maxSelectionsTextstring'최대 N개까지 선택할 수 있습니다'상한 도달 안내 문구 오버라이드
emptyTextstring'결과 없음'남은 후보가 없을 때 표시 문구
placeholderstring'입력하여 검색'칩이 없을 때 입력에 표시되는 문구
…restOmit<InputHTMLAttributes, 'onChange' | 'value' | 'defaultValue'>aria-label · disabled 등은 입력 요소로 전달

접근성#

입력이 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