@veiag/payload-cmdk
v1.0.6
Published
A command menu plugin for Payload CMS to enhance navigation and accessibility within the admin panel.
Readme
Payload CMDK
A powerful command menu plugin for Payload CMS that enhances navigation and accessibility within the admin panel. Quickly search and navigate through collections, globals, and custom actions using keyboard shortcuts.

Features
✨ Quick Search - Instantly search across all collections and globals
⌨️ Keyboard Shortcuts - Fully customizable keyboard shortcuts powered by react-hotkeys-hook
🔍 Collection Submenu - Search within collection documents by their title field
🎨 Custom Icons - Use any Lucide icon for collections and globals
🎯 Custom Items - Add custom actions and menu groups
🌍 i18n Support - Built-in English and Ukrainian translations, easily add your own
🖥️ Cross-platform - Optimized shortcuts for both macOS and Windows/Linux
Installation
npm install @veiag/payload-cmdk
# or
yarn add @veiag/payload-cmdk
# or
pnpm add @veiag/payload-cmdkQuick Start
The plugin works out of the box with minimal configuration:
import { payloadCmdk } from '@veiag/payload-cmdk'
import { buildConfig } from 'payload'
export default buildConfig({
// ... your config
plugins: [
payloadCmdk({
// Plugin works without any options!
}),
],
})This will:
- Add a search button to the admin panel
- Enable
⌘K(Mac) /Ctrl+K(Windows/Linux) keyboard shortcut - List all collections and globals in the command menu
- Enable collection submenu search
Configuration
Full Configuration Example
import { payloadCmdk } from '@veiag/payload-cmdk'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [
payloadCmdk({
// Keyboard shortcut to open the menu
shortcut: ['meta+k', 'ctrl+k'], // Default
// Search button configuration
searchButton: {
position: 'actions', // 'actions' | 'nav'
},
// Backdrop blur effect
blurBg: true, // Default
// Collection submenu configuration
submenu: {
enabled: true, // Default
shortcut: 'shift+enter', // 'shift+enter' | 'enter'
icons: {
posts: 'FileText',
users: 'User',
},
},
// Custom icons for collections and globals
icons: {
collections: {
posts: 'FileText',
pages: 'File',
media: 'Image',
users: 'Users',
},
globals: {
settings: 'Settings',
navigation: 'Menu',
},
},
// Collections/globals to ignore
slugsToIgnore: ['payload-migrations', 'payload-preferences'],
// Custom menu items
customItems: [
{
type: 'group',
title: 'Quick Actions',
items: [
{
type: 'item',
slug: 'view-site',
label: 'View Site',
icon: 'ExternalLink',
action: {
type: 'link',
href: 'https://your-site.com',
},
},
{
type: 'item',
slug: 'clear-cache',
label: 'Clear Cache',
icon: 'Trash2',
action: {
type: 'api',
method: 'POST',
href: '/api/cache/clear',
},
},
],
},
],
// Disable the plugin
disabled: false, // Default
}),
],
})Configuration Options
shortcut
Keyboard shortcut to open the command menu. Powered by react-hotkeys-hook.
- Type:
string | string[] - Default:
['meta+k', 'ctrl+k']
The default provides cross-platform support:
meta+k- Works on macOS (⌘K)ctrl+k- Works on Windows/Linux (Ctrl+K)
Examples:
// Single shortcut
shortcut: 'ctrl+shift+k'
// Multiple shortcuts for cross-platform support
shortcut: ['meta+k', 'ctrl+k']
// Custom combinations
shortcut: ['meta+/', 'ctrl+/']searchButton
Configuration for the search button displayed in the admin panel.
- Type:
{ position?: 'actions' | 'nav' } | false - Default:
{ position: 'actions' }
Options:
position: 'actions'- Display in the action buttons area (default)position: 'nav'- Display in the navigation sidebarfalse- Hide the search button completely (keyboard shortcut still works)
Examples:
// Display in navigation
searchButton: {
position: 'nav'
}
// Hide search button
searchButton: falseActions button position:

Navigation button position:

blurBg
Enable backdrop blur effect when the command menu is open.
- Type:
boolean - Default:
true
blurBg: false // Disable blur effectsubmenu
Configure submenu behavior for searching within collection documents.
- Type:
object - Default:
{ enabled: true, shortcut: 'shift+enter' }
Options:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| enabled | boolean | true | Enable/disable submenu functionality |
| shortcut | 'shift+enter' | 'enter' | 'shift+enter' | Keyboard shortcut to open submenu |
| icons | object | undefined | Custom icons for collection submenus |
Shortcut behavior:
shift+enter: Shift+Enter opens submenu, Enter navigates to collection listenter: Enter opens submenu, Shift+Enter navigates to collection list

Example:
submenu: {
enabled: true,
shortcut: 'enter',
icons: {
posts: 'FileText',
products: 'ShoppingCart',
}
}The submenu searches documents by their useAsTitle field (or id if not specified). You can configure this in your collection:
{
slug: 'posts',
admin: {
useAsTitle: 'title' // Submenu will search by this field
}
}icons
Customize icons for collections and globals using Lucide icon names.
- Type:
object - Default:
{ collections: {}, globals: {} }
Default icons:
- Collections:
Filesicon - Globals:
Globeicon
Example:
icons: {
collections: {
posts: 'FileText',
pages: 'File',
media: 'Image',
users: 'Users',
categories: 'Folder',
},
globals: {
settings: 'Settings',
navigation: 'Menu',
footer: 'Layout',
}
}Browse all available icons at lucide.dev/icons.
![]()
customItems
Add custom menu items and groups to the command menu.
- Type:
Array<CustomMenuItem | CustomMenuGroup> - Default:
[]
Custom Menu Item
{
type: 'item',
slug: 'unique-slug',
label: 'Item Label', // Can be localized
icon: 'LucideIconName', // Optional, from lucide.dev/icons
action: {
type: 'link' | 'api',
href: '/path/or/url',
method?: 'GET' | 'POST' | 'PUT' | 'DELETE', // For API actions
body?: { key: 'value' } // For API actions
}
}Custom Menu Group
{
type: 'group',
title: 'Group Title', // Can be localized
items: [
// Array of CustomMenuItem
]
}Example with localization:
customItems: [
{
type: 'group',
title: {
en: 'Quick Actions',
uk: 'Швидкі дії',
},
items: [
{
type: 'item',
slug: 'view-site',
label: {
en: 'View Site',
uk: 'Переглянути сайт',
},
icon: 'ExternalLink',
action: {
type: 'link',
href: 'https://your-site.com',
},
},
{
type: 'item',
slug: 'regenerate',
label: 'Regenerate Cache',
icon: 'RefreshCw',
action: {
type: 'api',
method: 'POST',
href: '/api/cache/regenerate',
},
},
],
},
]slugsToIgnore
Specify which collection/global slugs to exclude from the command menu.
- Type:
CollectionSlug[] | { ignoreList: CollectionSlug[], replaceDefaults?: boolean } - Default:
['payload-migrations', 'payload-preferences', 'payload-locked-documents']
Examples:
// Add to default ignore list
slugsToIgnore: ['internal-collection', 'test-data']
// Replace default ignore list completely
slugsToIgnore: {
ignoreList: ['my-hidden-collection'],
replaceDefaults: true
}disabled
Completely disable the plugin.
- Type:
boolean - Default:
false
disabled: process.env.DISABLE_COMMAND_MENU === 'true'Custom Translations
The plugin includes built-in translations for:
- 🇬🇧 English (
en) - 🇺🇦 Ukrainian (
uk)
You can add translations for other languages using Payload's i18n configuration:
import { buildConfig } from 'payload'
export default buildConfig({
i18n: {
supportedLanguages: {
//You can learn more about adding languages in the Payload docs
en,
uk,
de,
fr,
},
translations: {
de: {
cmdkPlugin: {
loading: 'Lädt...',
navigate: 'zum Navigieren',
noResults: 'Keine Ergebnisse gefunden',
open: 'zum Öffnen',
search: 'Sammlungen, Globals durchsuchen...',
searchIn: 'Suchen in {{label}}',
searchInCollection: 'in Sammlung suchen',
searchShort: 'Suchen',
},
},
fr: {
cmdkPlugin: {
loading: 'Chargement...',
navigate: 'pour naviguer',
noResults: 'Aucun résultat trouvé',
open: 'pour ouvrir',
search: 'Rechercher collections, globals...',
searchIn: 'Rechercher dans {{label}}',
searchInCollection: 'pour rechercher dans la collection',
searchShort: 'Rechercher',
},
},
},
},
plugins: [
payloadCmdk({
// Your config
}),
],
})Available Translation Keys
All translation keys are under the cmdkPlugin namespace:
| Key | Description | Example (EN) |
|-----|-------------|--------------|
| search | Main search placeholder | "Search collections, globals..." |
| searchShort | Short search label | "Search" |
| searchIn | Submenu search placeholder | "Search in {{label}}" |
| loading | Loading state | "Loading..." |
| noResults | No results state | "No results found" |
| navigate | Footer hint for navigation | "to navigate" |
| searchInCollection | Footer hint for collection search | "to search in collection" |
| open | Footer hint for opening documents | "to open" |
Keyboard Shortcuts
Global Shortcuts
| Shortcut | Action |
|----------|--------|
| ⌘K / Ctrl+K | Open/close command menu |
| Esc | Close menu or go back in submenu |
| ↑ ↓ | Navigate items |
| Enter | Select item or navigate to collection |
| Shift+Enter | Search within collection (default) |
In Submenu
| Shortcut | Action |
|----------|--------|
| Esc | Go back to main menu |
| Enter | Open selected document |
Examples
Minimal Setup
export default buildConfig({
plugins: [payloadCmdk()],
})Custom Shortcuts Only
export default buildConfig({
plugins: [
payloadCmdk({
shortcut: ['meta+/', 'ctrl+/'],
searchButton: false, // Hide button, only use keyboard
}),
],
})With Custom Actions
export default buildConfig({
plugins: [
payloadCmdk({
customItems: [
{
type: 'item',
slug: 'documentation',
label: 'View Documentation',
icon: 'BookOpen',
action: {
type: 'link',
href: 'https://docs.your-site.com',
},
},
],
}),
],
})Full Custom Theme
export default buildConfig({
plugins: [
payloadCmdk({
icons: {
collections: {
posts: 'Newspaper',
pages: 'FileText',
media: 'Image',
categories: 'FolderTree',
tags: 'Tag',
users: 'UserCircle',
comments: 'MessageCircle',
},
globals: {
header: 'LayoutTemplate',
footer: 'Layout',
settings: 'Settings',
navigation: 'Menu',
seo: 'Search',
},
},
submenu: {
enabled: true,
icons: {
posts: 'FileText',
pages: 'File',
media: 'Image',
},
},
}),
],
})Troubleshooting
Objects are not valid as a React childerror: Ensure youradmin.useAsTitlefield is a string and not an object. Currently, plugin doesn't have any safeguards for non-string title fields.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Issues
Found a bug or have a feature request? Please open an issue on GitHub.
License
MIT © VeiaG
