Command Palette
Bảng lệnh ⌘K tìm ra mọi trang, mọi thao tác chỉ sau vài phím gõ
.zip · HTML / CSS / JS · v1.0.0
Miễn phí — không cần tài khoản hay email. Luôn là bản mới nhất.
Đang chạy trực tiếp
Giới thiệu
Cách nhanh nhất để đi lại trong một ứng dụng là gõ thứ mình cần. Bấm ⌘K (Ctrl+K trên Windows và Linux), một tấm kính mờ hiện ra trên nền trang được làm tối và nhoè nhẹ. Bắt đầu gõ: "gs" ra "Go to settings", "tgl" ra "Toggle theme", "cai dat" ra "Cài đặt". Mũi tên xuống, Enter, xong — và lần sau lệnh đó đã chờ sẵn ở đầu danh sách, mục Gần đây.
- Tìm kiếm mờ ưu tiên đầu từ và các chữ liền nhau, nên kết quả đúng nhất luôn đứng đầu
- Lệnh được gom theo nhóm, mỗi lệnh có thể kèm icon và gợi ý phím tắt
- Mỗi lệnh gọi một hàm hoặc mở một link; Next.js và các router khác cắm vào bằng một tuỳ chọn
- Dựng trên
<dialog>gốc: giữ focus, khoá trang phía sau và Esc có sẵn, không cần mẹo overlay - Mọi màu, bo góc và thời gian đều là CSS custom property; sáng và tối tự theo trang của bạn
- Không cần cài gì: một file CSS và một script nhỏ, hoặc một component React
Tính năng
- Mở bằng ⌘K / Ctrl+K hoặc bất kỳ nút nào bạn đánh dấu; Esc hoặc bấm ra ngoài để đóng
- Tìm kiếm mờ (fuzzy): bỏ sót chữ hay gõ không dấu vẫn ra, chữ khớp được tô sáng
- Kết quả xếp theo độ khớp và gom theo nhóm
- Lệnh vừa dùng hiện lên đầu, nhớ cả sau khi tải lại trang
- Mỗi lệnh chạy một hàm hoặc mở một đường dẫn (qua router của bạn nếu muốn)
- Giao diện kính mờ, đủ sáng và tối, đổi màu bằng CSS custom property
- Bản HTML/CSS/JS thuần và bản React (dùng được với Next.js)
- Không phụ thuộc thư viện, khoảng 8 KB sau gzip (cả script lẫn CSS)
Cách dùng
Gắn stylesheet và script một lần, rồi đưa danh sách lệnh vào. Script tự dựng dialog; mọi phần tử có
data-command-palette-open đều mở được bảng lệnh, phím ⌘K / Ctrl+K cũng vậy:
<link rel="stylesheet" href="command-palette.css" />
<script src="command-palette.js" defer></script>
<button type="button" data-command-palette-open>
Tìm kiếm… <kbd data-command-palette-hotkey>⌘K</kbd>
</button>
<script>
document.addEventListener("DOMContentLoaded", () => {
const palette = CommandPalette.create({
placeholder: "Gõ lệnh hoặc tìm kiếm…",
items: [
{ id: "home", title: "Trang chủ", section: "Điều hướng", href: "/" },
{ id: "billing", title: "Thanh toán", section: "Điều hướng", keywords: ["hoá đơn", "gói"], href: "/billing" },
{ id: "theme", title: "Đổi giao diện", section: "Thao tác", icon: "🌓", shortcut: ["T"], perform: toggleTheme },
],
});
});
</script>create trả về { open, close, toggle, setItems, isOpen, destroy }; setItems thay danh sách lệnh
bất cứ lúc nào (chẳng hạn khi tải từ API). Thẻ <kbd data-command-palette-hotkey> được viết lại
thành "⌘K" trên thiết bị Apple và "Ctrl+K" ở nơi khác. icon là chữ (một emoji) hoặc một DOM node,
chẳng hạn <svg> lấy từ <template> — mỗi dòng nhận một bản sao.
Tuỳ chọn:
| Tuỳ chọn | Mặc định | Tác dụng |
|---|---|---|
items |
— | Danh sách lệnh (xem bên dưới) |
placeholder |
"Type a command or search…" |
Chữ gợi ý trong ô tìm kiếm |
hotkey |
"mod+k" |
mod là ⌘ trên thiết bị Apple, Ctrl ở nơi khác; ví dụ "ctrl+shift+p", "/"; false để tắt |
recent |
true |
Lệnh vừa dùng lên đầu; false, hoặc { key, limit } (khoá localStorage, mặc định giữ 5) |
trigger |
"[data-command-palette-open]" |
Bấm vào phần tử khớp selector này sẽ mở bảng lệnh; false để tắt |
navigate |
location.assign |
Cách mở href |
onRun(item) |
— | Gọi mỗi khi chạy một lệnh, trước khi lệnh chạy |
onOpenChange(open) |
— | Gọi khi mở hoặc đóng |
texts |
Tiếng Anh | Mọi chữ hiển thị hoặc đọc lên, để dịch (xem core/texts.ts) |
container |
document.body |
Nơi gắn dialog |
Bản tiếng Việt cho texts:
texts: {
label: "Bảng lệnh",
inputLabel: "Tìm lệnh",
listLabel: "Lệnh",
recent: "Gần đây",
close: "Đóng",
empty: (query) => `Không có kết quả cho “${query.trim()}”`,
count: (count) => `${count} kết quả`,
hintMove: "để di chuyển",
hintRun: "để chạy",
hintClose: "để đóng",
}{
id: "billing", // duy nhất và cố định: mục "gần đây" nhớ theo id
title: "Thanh toán", // hiển thị và được tìm
section: "Điều hướng", // tiêu đề nhóm (tuỳ chọn)
keywords: ["hoá đơn"], // cũng được tìm nhưng không hiển thị (tuỳ chọn)
shortcut: ["G", "B"], // hiện dạng phím <kbd> — chỉ là gợi ý, bạn tự gắn phím (tuỳ chọn)
icon: "💳", // chữ hoặc DOM node; trong React là React node bất kỳ (tuỳ chọn)
href: "/billing", // mở khi không có perform (tuỳ chọn)
perform: () => {}, // chạy khi được chọn (tuỳ chọn)
}Chạy một lệnh sẽ đóng bảng lệnh, ghi nhớ vào mục gần đây, rồi gọi perform hoặc mở href.
Chép CommandPalette.tsx, command-palette.css và thư mục core vào dự án:
import { useState } from "react";
import { CommandPalette } from "./CommandPalette";
const items = [
{ id: "home", title: "Trang chủ", section: "Điều hướng", href: "/" },
{ id: "theme", title: "Đổi giao diện", section: "Thao tác", icon: <MoonIcon />, perform: toggleTheme },
];
export function Search() {
const [open, setOpen] = useState(false);
return (
<>
<button type="button" onClick={() => setOpen(true)}>Tìm kiếm… ⌘K</button>
<CommandPalette items={items} open={open} onOpenChange={setOpen} />
</>
);
}Bỏ open đi thì component tự quản lý trạng thái (defaultOpen để mở sẵn); phím tắt hoạt động trong
cả hai cách. Mọi tuỳ chọn ở trên đều là prop (placeholder, hotkey, recent, texts, navigate,
onRun), thêm className. Giữ items ổn định (useMemo hoặc hằng số ngoài component) để danh sách
không bị xếp hạng lại sau mỗi lần render. React 18 hoặc 19.
Component bắt đầu bằng "use client", nên dùng được trong mọi page hay server component. Truyền
router vào để link không tải lại trang: navigate={router.push} với useRouter() từ
next/navigation. Với Pages Router, chuyển dòng import CSS vào pages/_app.
Đặt các biến sau trên .command-palette (hoặc class của bạn, qua className trong React):
| Biến | Đổi gì |
|---|---|
--palette-surface, --palette-border, --palette-blur |
Tấm kính mờ |
--palette-aurora-1, --palette-aurora-2, --palette-glow |
Các vệt màu trên tấm kính và quầng bóng |
--palette-text, --palette-muted |
Màu chữ chính và chữ phụ |
--palette-accent, --palette-accent-2 |
Chữ khớp, icon tìm kiếm, vạch đánh dấu lựa chọn |
--palette-active, --palette-chip |
Nền lựa chọn đang chọn, nền phím và icon |
--palette-backdrop |
Lớp tối phủ lên trang phía sau |
--palette-width, --palette-top, --palette-max-height |
Kích thước và vị trí |
--palette-radius, --palette-option-radius |
Bo góc |
--palette-enter, --palette-exit, --palette-ease |
Hiệu ứng mở và đóng |
Màu dùng light-dark(): tự theo color-scheme của trang.
Hỏi về sản phẩm này
Chưa chắc có hợp dự án của bạn? Cứ hỏi — câu trả lời lấy từ chính trang này.
Lịch sử phiên bản
1.0.0First releaseMới nhất
Plain HTML/CSS/JS and React builds. ⌘K / Ctrl+K hotkey, fuzzy search with highlights, sections, recent commands, full keyboard and screen-reader support, light and dark.
- Bản sửa lỗi và tính năng mới đều có ngay ở nút tải này — file tải về luôn là bản mới nhất.

