Command
검색 입력 + 필터된 명령 리스트(명령 팔레트 표면) — combobox + listbox를 aria-activedescendant로 연결. 검색은 label 부분 일치, 비제어(query 내부 소유).
마지막 업데이트 2026-06-11
한눈에#
⌘K로 여는 명령 팔레트 — 검색으로 명령을 좁히고 ↑/↓·Enter로 골라 실행합니다. 여러 액션을 모으는 단축 진입점입니다.
- 새 파일 만들기
- 프로젝트 열기
- 문서 검색
- 테마 전환
- 배포 (권한 필요)
- 설정
↑/↓로 이동(비활성 건너뜀·순환) · Enter 또는 클릭으로 선택
- ⌘K 명령 팔레트
- combobox + listbox
- label 부분 일치
- 비제어 검색
입력해 필터하고 ↑/↓로 이동 후 Enter로 선택 — 포커스는 입력에 머물고 aria-activedescendant가 활성 항목을 가리킵니다
선택 결과를 보여주기 위해 데모 래퍼가 onSelect를 받습니다 — Command 자체의 검색·탐색은 핸들러 없이도 동작합니다(비제어).
사용 시점#
검색으로 좁혀 명령을 실행하는 팔레트면 Command — 단순 검색 이동이나 고정 액션 메뉴는 다른 컴포넌트입니다.
- 새 파일 만들기
- 프로젝트 열기
- 문서 검색
- 테마 전환
- 배포 (권한 필요)
- 설정
↑/↓로 이동(비활성 건너뜀·순환) · Enter 또는 클릭으로 선택
⌘K 단축 진입점에서 검색으로 명령을 좁혀 ↑/↓·Enter로 실행
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
- 새 파일 만들기
- 프로젝트 열기
- 문서 검색
- 테마 전환
import { Command } from '@wds/ui-web';
<Command
items={[
{ value: 'new', label: '새 파일 만들기' },
{ value: 'open', label: '프로젝트 열기' },
{ value: 'search', label: '문서 검색' },
{ value: 'theme', label: '테마 전환' },
]}
/>변형#
변형이 없습니다 — 항목 단위 disabled로 "보이지만 선택 불가" 상태를
표현합니다(키보드 탐색이 건너뛰고, 클릭·Enter가 무시됩니다). 모달 팔레트가
필요하면 Modal과 합성하세요.
크기#
단일 크기입니다 — 입력 높이 3rem, 리스트 최대 높이 20rem(초과 시 스크롤).
상태#
- 활성 항목 —
aria-activedescendant대상,color.surface-hover배경 - 빈 결과 — 일치 항목이 없으면 리스트 대신
emptyText를role="status"로 표시(검색어를 바꾸면 복귀) - Focus — 루트
:focus-within에input.border-focus보더 + 18% 링 - Disabled 항목 —
color.disabled-fg잉크 + 커서 차단
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
items | readonly CommandItem[] | — | { value, label, disabled? } 배열 — label이 검색 대상 |
onSelect | (value: string) => void | — | 항목 선택 콜백 (Enter 또는 클릭) |
placeholder | string | '검색어를 입력하세요' | 검색 입력 플레이스홀더 |
searchLabel | string | '명령 검색' | 검색 입력·리스트의 aria-label |
emptyText | string | '결과가 없습니다' | 빈 결과 문구 — role="status"로 보조기술에 알림 |
className | string | — | 루트(div)에 적용 |
접근성#
입력이 role="combobox" + aria-autocomplete="list", 리스트가
role="listbox"입니다. 포커스는 입력에 머물고 aria-activedescendant가
활성 항목 id를 가리킵니다(클릭도 mousedown을 막아 입력 포커스 유지).
| 키 | 동작 |
|---|---|
| 문자 입력 | label 부분 일치(대소문자 무시) 필터 — 활성 항목은 첫 활성 매치로 리셋 |
↓ / ↑ | 활성 항목 순환 이동 — 비활성 항목 건너뜀 |
Enter | 활성 항목 선택 — onSelect(value) 호출(빈 결과면 무시) |
- 활성 항목은
aria-selected, 비활성 항목은aria-disabled로 보고 - 빈 결과는
role="status"라이브 영역 — 필터 결과 소멸을 보조기술에 알림 - 검색 대상은
label텍스트 — 약어 별칭 검색은 지원하지 않습니다
토큰#
component 토큰 없이 Input의 component 토큰(input.border-focus)과 semantic을
직접 소비합니다(신설 기준 §4 미충족).
| 속성 | 토큰 |
|---|---|
| 루트 | color.surface + color.border · radius.lg · shadow.sm |
| 포커스 링 | input.border-focus + color.primary 18% 링 (:focus-within) |
| 검색 입력 | font.size-body-1 · placeholder color.text-placeholder |
| 검색 아이콘 | icon.size-md · color.text-muted |
| 항목 | font.size-body-2 · hover/활성 color.surface-hover · pressed color.surface-pressed |
| 비활성 항목 | color.disabled-fg |
| 빈 결과 | color.text-muted · 패딩 space.8 |
| 모션 | duration.fast + ease.standard |