Palette de commandes
Règles
- Utiliser la bibliothèque
cmdk — recherche floue intégrée, accessible, rapide et composable
- Déclencheur :
Cmd+K (Mac) / Ctrl+K (Windows/Linux) — enregistrer un écouteur de clavier global
- Grouper les actions : Navigation (pages), Commandes (actions), Récent (dernière utilisation) — afficher les en-têtes de groupe
- Navigation au clavier : touches fléchées pour se déplacer, Entrée pour sélectionner, Échap pour fermer — tout est géré par cmdk
- Recherche floue : cmdk filtre automatiquement — mise en évidence des correspondances avec classement par score
- Éléments récents : stocker les 5 à 10 derniers éléments sélectionnés dans localStorage — les afficher en haut lorsque la saisie est vide
- Actions dynamiques : enregistrer des actions depuis différentes parties de l'application — contextuelles (afficher différentes actions sur différentes pages)
- État de chargement : résultats de recherche asynchrones (ex. recherche via API) — afficher un indicateur de chargement dans la zone des résultats
Exemples
import { Command } from "cmdk";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
function CommandPalette() {
const [open, setOpen] = useState(false);
const router = useRouter();
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((prev) => !prev);
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, []);
return (
<Command.Dialog open={open} onOpenChange={setOpen} label="Palette de commandes">
<Command.Input placeholder="Rechercher ou taper une commande..." />
<Command.List>
<Command.Empty>Aucun résultat trouvé.</Command.Empty>
<Command.Group heading="Récent">
{recentItems.map((item) => (
<Command.Item key={item.id} onSelect={() => { router.push(item.href); setOpen(false); }}>
{item.label}
</Command.Item>
))}
</Command.Group>
<Command.Group heading="Navigation">
<Command.Item onSelect={() => { router.push("/dashboard"); setOpen(false); }}>
Tableau de bord
</Command.Item>
<Command.Item onSelect={() => { router.push("/settings"); setOpen(false); }}>
Paramètres
</Command.Item>
</Command.Group>
<Command.Group heading="Commandes">
<Command.Item onSelect={() => { toggleTheme(); setOpen(false); }}>
Activer/désactiver le mode sombre
</Command.Item>
<Command.Item onSelect={() => { logout(); setOpen(false); }}>
Se déconnecter
</Command.Item>
</Command.Group>
</Command.List>
</Command.Dialog>
);
}
À éviter
- Construire une recherche floue personnalisée — cmdk gère le filtrage, le score et le classement prêts à l'emploi
- Oublier
e.preventDefault() sur Cmd+K — sans cela, la barre de recherche ou d'adresse par défaut du navigateur s'ouvre
- Ne pas gérer la touche Échap — cmdk gère cela via
onOpenChange, mais assurez-vous que le focus revient à l'élément précédent
- Actions uniquement statiques — enregistrer les actions dynamiquement depuis le contexte de la page (ex. "Modifier cet article" uniquement sur les pages d'article)
- Absence d'état vide — toujours afficher "Aucun résultat trouvé" lorsque la recherche ne correspond à rien