Command
StabilnySzybka, projektowana z myślą o klawiaturze lista poleceń i wyników z wyszukiwaniem rozmytym — osadzona w stronie albo jako paleta ⌘K nad jej treścią.
Anatomia
- 1Pole wyszukiwaniaFiltruje listę w trakcie pisania. Fokus zostaje tutaj, a strzałki przesuwają podświetlenie.
- 2Nagłówek grupyOpisuje zestaw powiązanych wyników. Nagłówki zostają na miejscu, gdy ich pozycje są filtrowane.
- 3Podświetlona pozycjaPozycja, którą uruchomi Enter. Podświetlenie podąża za strzałkami i kursorem.
- 4SkrótKlawisze, które uruchamiają pozycję bez otwierania palety. Pełni wyłącznie funkcję informacyjną.
Instalacja
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/command.jsonUżycie
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"<Command>
<CommandInput placeholder="Type a command or search…" />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem onSelect={() => openCalendar()}>Calendar</CommandItem>
<CommandItem onSelect={() => openEmoji()}>Search emoji</CommandItem>
</CommandGroup>
</CommandList>
</Command>Command opiera się na cmdk. W trakcie pisania filtruje pozycje i układa je według trafności, zawsze trzyma jedną z nich podświetloną i uruchamia jej onSelect po naciśnięciu Enter lub kliknięciu. Gdy zmieniają się wyniki, lista płynnie animuje swoją wysokość, więc paleta nigdy nie skacze.
Przykłady
Osadzony w treści
Renderuj Command bezpośrednio, gdy selektor albo launcher ma być osadzony w stronie. Grupy ułatwiają przeglądanie wyników, a CommandShortcut podpowiada szybszą drogę.
Paleta poleceń
CommandDialog umieszcza listę poleceń w oknie Dialog zakotwiczonym wysoko na ekranie, więc wyniki rosną w dół, a pole wyszukiwania się nie przesuwa. Przypisz paletę do skrótu ⌘ K (ten przykład używa ⌘ J, żeby nie kolidować z wyszukiwarką tej strony, zbudowaną z tego samego komponentu) i dodaj CommandFooter z podpowiedziami klawiszy.
const [open, setOpen] = React.useState(false)
React.useEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === "k" && (event.metaKey || event.ctrlKey)) {
event.preventDefault()
setOpen((value) => !value)
}
}
document.addEventListener("keydown", onKeyDown)
return () => document.removeEventListener("keydown", onKeyDown)
}, [])
return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Search…" />
<CommandList>{/* groups and items */}</CommandList>
<CommandFooter />
</CommandDialog>
)Stan pusty
CommandEmpty renderuje się tylko wtedy, gdy nic nie pasuje. Zadbaj, żeby był przydatny: powiedz, czego szukano, i zaproponuj, co zrobić dalej.
Słowa kluczowe i aliasy
Użytkownicy szukają własnymi słowami. Dodaj keywords, żeby tryb ciemny znajdował Wygląd, a faktura — Płatności. Słowa kluczowe liczą się przy dopasowaniu, ale nie są wyświetlane.
Wybór wielokrotny
W selektorach, w których można zaznaczyć kilka wartości, nie zamykaj listy po wybraniu pozycji i ustawiaj na pozycjach data-checked — prfct wyświetli na ich końcu znacznik wyboru.
Wyniki asynchroniczne
Gdy wyniki przychodzą z serwera, wyłącz wbudowane filtrowanie przez shouldFilter={false}, steruj wyszukiwaniem za pomocą value i onValueChange na CommandInput i renderuj pobrane pozycje.
<Command shouldFilter={false}>
<CommandInput value={query} onValueChange={setQuery} />
<CommandList>
{isLoading && <CommandEmpty>Searching…</CommandEmpty>}
{results.map((result) => (
<CommandItem key={result.id} value={result.id} onSelect={open}>
{result.title}
</CommandItem>
))}
</CommandList>
</Command>Wytyczne
Kiedy używać
- Jako globalna paleta (⌘ K) do nawigacji i akcji w aplikacjach, które mają więcej niż kilka ekranów.
- Jako osadzona lista z wyszukiwaniem tam, gdzie Select już nie wystarcza: przypisane osoby, etykiety, emoji, pliki.
Kiedy nie używać
- Do wyboru pojedynczej wartości w formularzu — kontrolką formularza jest Combobox, z widoczną wartością, walidacją i etykietą.
- Do krótkich, stałych list akcji — Dropdown Menu szybciej się przegląda, niż przeszukuje.
- Gdy paleta miałaby być jedyną drogą do polecenia. Paleta to skrót; wszystko, co w niej jest, powinno istnieć także w interfejsie.
Nazywanie pozycji
Nazywaj pozycje tak, jak ludzie ich szukają: miejsca docelowe rzeczownikami (Ustawienia, Płatności), akcje wyrażeniami z czasownikiem (Utwórz projekt…, Zaproś do zespołu…). Wielokropek dodawaj do pozycji, które wymagają dalszych danych. Grupuj wyniki według rodzaju — Nawigacja, Akcje, Ostatnie — a najbardziej prawdopodobne trzymaj w pierwszej grupie.
Kolejność wyników
W trakcie pisania pozycje są szeregowane w obrębie swojej grupy — najpierw dopasowania od początku słowa i całe słowa, na końcu litery rozrzucone po etykiecie — ale grupy zachowują kolejność, w jakiej je renderujesz. Na początku umieść grupę, po którą ludzie sięgają najczęściej. W palecie, która przeszukuje wiele sekcji, np. dokumentację, renderuj wyniki jako jedną grupę, dopóki zapytanie nie jest puste — wtedy podświetlone jest zawsze najlepsze trafienie. Ogranicz keywords do kilku słów: przy długich opisach pasuje niemal każde zapytanie.
Wydajność
cmdk bez trudu radzi sobie z kilkoma tysiącami pozycji. Przy większej liczbie filtruj na serwerze (zobacz Wyniki asynchroniczne) albo ogranicz liczbę renderowanych wyników — lista nie jest wirtualizowana.
Dostępność
Command implementuje wzorzec WAI-ARIA combobox: pole ma rolę combobox i steruje listą listbox, a podświetlona opcja (option) jest ogłaszana przez aria-activedescendant, podczas gdy fokus zostaje w polu — dzięki temu można jednocześnie pisać i nawigować.
| Klawisz | Działanie |
|---|---|
↓↑ | Podświetla następną lub poprzednią pozycję. Z ustawionym loop przechodzi z końca listy na początek i odwrotnie. |
HomeEnd | Podświetla pierwszą lub ostatnią pozycję. |
⌘↓⌘↑ | Przeskakuje do ostatniej lub pierwszej pozycji. |
Alt↓Alt↑ | Przeskakuje do pierwszej pozycji następnej lub poprzedniej grupy. |
CtrlNCtrlJ | Podświetla następną pozycję (wyłączysz to przez vimBindings={false}). |
CtrlPCtrlK | Podświetla poprzednią pozycję. |
Enter | Wywołuje onSelect podświetlonej pozycji. |
Esc | W CommandDialog zamyka paletę i przywraca fokus do elementu, który ją otworzył. |
- Nazwij paletę.
CommandDialogrenderuje wizualnie ukryty tytuł i opis — przekaż sensowne propsytitleidescription. - Wyłączone pozycje są pomijane podczas nawigacji i ogłaszane jako niedostępne.
- Ikony w pozycjach są dekoracyjne; ogłaszany i dopasowywany jest tekst pozycji.
Dokumentacja API
Command
Komponent główny z cmdk.
CommandDialog
Command wewnątrz okna Dialog. Umieść CommandInput, CommandList i CommandFooter bezpośrednio w środku — okno samo dostarcza komponent główny Command (jeśli przekażesz własny Command, to on posłuży jako komponent główny). Przyjmuje propsy komponentu głównego Dialog (open, onOpenChange, …), a ponadto:
CommandInput
CommandItem
CommandGroup
CommandList, CommandEmpty, CommandSeparator, CommandShortcut, CommandFooter
CommandList to przewijany obszar wyników; jego wysokość nie przekracza min(24rem, 60dvh) i jest animowana. CommandEmpty renderuje się, gdy nie ma wyników. CommandSeparator przyjmuje alwaysRender, żeby pozostać widocznym podczas wyszukiwania. CommandShortcut to czysto prezentacyjna podpowiedź na końcu pozycji. CommandFooter domyślnie renderuje podpowiedzi nawigacji — przekaż własne elementy potomne, żeby je zastąpić.