Spotlight
검색창에서 자라나는 패널로 기록·사람·출처를 찾아 이동.
- 라이브러리 전용
개요
미리보기
예시
상태
닫힘 (트리거)
단축키 표시 없음
비었을 때 (최근 · 제안)
결과 그룹
결과 없음
불러오는 중
오류
이렇게 · 이렇게 하지 않기
- 이렇게 하지 않기 검색과 이동만 하고 되돌릴 수 없는 행동은 실행하지 않는다.
- 이렇게 하지 않기 패널에 키 안내(Esc, Enter, ↑↓)를 그리지 않는다. 키는 그대로 동작하고 접근성 문서에만 적는다. 닫기는 배경 누르기·폰의 취소, 지우기는 (×).
- 이렇게 결과가 없으면 읽은 기간과 함께 말한다.
- 이렇게 하지 않기 최근 항목을 “추천”이나 사용량 순으로 다시 정렬하지 않는다. 사용자가 연 순서만 따른다.
- 이렇게 하지 않기 role="menu"로 만들지 않는다. 검색 결과는 고르는 목록이므로 combobox + listbox다.
- 이렇게 21st 참고(라운드 5 검색): Apple Spotlight(samitkapoor — 크고 조용한 입력, 같은 면 위의 결과, 한 줄씩 나타나는 행, 고른 행에만 보이는 ›), Center Morph Modal(starc007, demo 29357 — 펼쳐지는 동안 같은 둥글기, 보조 버튼은 한 박자 뒤, 옅은 배경과 작은 blur), Action Search Bar(kokonutd, demo 555 — 입력 중 몇 px 올라오는 stagger). blob 필터·blur 등장·스프링과 ESC 안내 줄은 버렸다.
- 이렇게 21st 참고: Command Palette(ddoemonn — combobox/listbox·aria-activedescendant·“일치 없음” 상태 문장, 배경 200ms·패널 160ms 불투명도), Command Menu with Global Search(ephraimduncan — 최근 연 항목 그룹), Command Menu(uvain — 그룹과 단축키 힌트), Command(wensity — ↑↓ 안내 줄). properui의 role=menu, serafimcloud의 blur 등장, 패널 scale(.95)은 버렸다.
토큰과 속성
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
label? | string | | 대화상자 이름. 비우면 “빠른 검색”. |
placeholder? | string | | 입력란 예시이자 트리거 문구. 비우면 “기록, 경험, 설정 검색”. 라벨을 대신하지 않는다. |
open? | boolean | false | 바뀌면 열고 닫는다(showModal). 카탈로그는 비모달로 그린다. |
groups | readonly SpotlightGroup[] | — | { id, label, layout?, items: { id, label, description?, href?, keywords?, icon?, logo?, avatar?, person?, query? }[] }. 앞에는 logo(출처 로고) > avatar(사람) > icon 순으로 그린다. person은 사실 줄 뒤에 붙고, query가 있으면 고를 때 그 말로 검색한다. onQueryChange가 없으면 여기서 거른다(label · description · person · keywords). 미리보기: 기록 3 · 경험 1 · 설정 3. |
recent? | readonly SpotlightItem[] | — | 검색어가 없을 때 “최근”. 사용자가 연 순서 그대로, 다시 정렬하지 않는다. |
suggestions? | readonly SpotlightGroup[] | — | 검색어가 없을 때 최근 아래에, 결과가 없을 때 안내 아래에 보인다. layout="tiles"는 사람·출처를 한 줄 타일로 그린다. 사람·출처 항목에 query를 주면 고를 때 그 말로 검색한다. |
defaultQuery? | string | | 처음 검색어. |
status? | 'ready' | 'loading' | 'error' | ready | 비동기 검색 상태. 최근·결과·결과 없음은 검색어에서 정해진다. |
scannedRange? | string | 3월 4일–10월 21일 | 결과가 없을 때 함께 말하는 읽은 기간. 비우면 기간 없이 말한다. |
noResultsHint? | string | | 결과 없음 아래의 도움 한 줄. 비우면 “낱말을 줄이거나 다른 말로 찾아보세요.” |
shortcutHint? | boolean | true | 트리거에 ⌘K / Ctrl K 표시를 보인다(shortcut이 켜졌을 때만). 꺼도 단축키는 동작한다(휴대폰, 좁은 바). |
trigger? | 'button' | 'focus-only' | button | button: 검색 칸 모양의 트리거. focus-only: 탭 순서에는 남고 키보드 포커스를 받을 때만 화면 위쪽에 보인다(SkipLink 방식). 화면이 자기 버튼(독의 찾기)으로 open을 열 때 쓴다. 화면이 트리거 DOM을 숨기지 않는다. |
shortcut? | boolean | true | 문서에 ⌘K / Ctrl+K를 등록한다(화면당 하나). 카탈로그 미리보기는 카탈로그 검색과 겹치지 않게 등록하지 않는다. |
onSelect?: (item) => void | — | — | 항목을 고르면 호출. 없으면 href로 이동한다. 이동 뒤 초점은 그 화면의 h1이 받는다(화면 책임). |
onQueryChange?: (query) => void | — | — | 비동기 검색. 주면 내장 필터가 꺼지고 groups가 결과가 된다. 진행 중에는 status="loading". |
--cb-spotlight-width (CSS, on an ancestor) | — | — | 트리거의 최대 너비(기본 384px). 넓은 바에서 화면이 조상에 설정한다. 화면은 트리거 DOM을 선택하지 않는다. |
onOpenChange · onRetry · announce() | — | — | 열림 변화, 오류 다시 시도, LiveAnnouncer polite(입력이 멈추고 500ms 뒤 “결과 12개”). |
| 그 밖의 속성 | — | — | id, data-* 등 네이티브 div 속성은 바깥 래퍼로 전달된다. className·style·children은 받지 않는다. |
접근성
키보드: ⌘K / Ctrl+K 열기(입력란 안에서도) · ↑↓ 이동(순환) · Enter 실행 · Esc: 검색어가 있으면 지우고, 비었으면 닫기(화면에는 안내하지 않는다). 한국어·중국어 입력 조합 중에는 키를 가로채지 않는다.
- <dialog> + showModal. 입력은 role="combobox" aria-controls aria-activedescendant, 결과는 role="listbox" → group(aria-labelledby) → option(aria-selected). 초점은 입력에 남는다.
- 열면 입력, 닫으면 트리거로 초점. 일치 부분은 굵게 + 밑줄(색만이 아님).
- 모션(WAAPI, 모션 코어 토큰, transform·opacity만, 오버슈트 없음): 면이 검색창 상자에서 패널 상자로 move(280ms) 동안 옮겨가고, 입력 줄은 하나의 scale로 따라온다(글자가 늘어나지 않음). 결과는 한 박자 뒤 stagger. 퇴장은 ×0.7로 검색창에 돌아간다. 폰(≤ 40rem)은 전체 화면 시트가 24px 올라온다. reduce면 fade만.