Tools
Tools: Building Command Palettes with kbar in React
2026-01-19
0 views
admin
Prerequisites ## Installation ## Project Setup ## First Example / Basic Usage ## Understanding the Basics ## Practical Example / Building Something Real ## Common Issues / Troubleshooting ## Next Steps ## Summary ## SEO Keywords kbar is a fast, portable, and extensible ⌘K interface for React applications. It provides a complete command palette solution with keyboard shortcuts, search functionality, and customizable UI components. kbar makes it easy to create powerful command menus similar to those found in VS Code, Linear, and other modern applications. This guide walks through setting up and creating command palettes using kbar with React, from installation to a working implementation. Before you begin, make sure you have: Install kbar using your preferred package manager: After installation, your package.json should include: kbar requires wrapping your application with KBarProvider and including the UI components. Let's set up the basic structure. Let's create a simple command palette. Update your src/App.jsx: This creates a basic command palette that opens with ⌘K (or Ctrl+K) and displays searchable actions. kbar provides command palette components: Here's an example with more features: Let's build a comprehensive command palette with grouped actions and navigation: This example demonstrates: Command palette not opening: Make sure you've wrapped your app with KBarProvider. The default shortcut is ⌘K (Mac) or Ctrl+K (Windows/Linux). Check browser console for errors. Actions not showing: Verify that your actions array is properly formatted with required fields (id, name, perform). Check that KBarResults is inside KBarAnimator. Search not working: Ensure KBarSearch is included and useMatches hook is used correctly. Actions are filtered by name and keywords automatically. Styling issues: kbar is unstyled by default. Add custom styles to KBarPositioner, KBarAnimator, and result items. Use inline styles or CSS classes. Keyboard shortcuts not working: Check that no other components are intercepting keyboard events. Ensure KBarProvider is at the root level of your app. Portal rendering issues: Make sure KBarPortal is included. The portal renders the command palette outside the normal DOM hierarchy. Now that you have an understanding of kbar: You've successfully set up kbar in your React application and created command palettes with keyboard shortcuts, search functionality, and customizable actions. kbar provides a fast, portable solution for building ⌘K interfaces in React applications. kbar
kbar React
kbar command palette
React ⌘K menu
kbar installation
React command menu
kbar tutorial
React command palette library
kbar example
React keyboard shortcuts
kbar setup
React cmd+k interface
kbar getting started
React searchable menu
kbar advanced usage Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
npm install kbar Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm install kbar COMMAND_BLOCK:
npm install kbar CODE_BLOCK:
yarn add kbar Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
yarn add kbar CODE_BLOCK:
yarn add kbar CODE_BLOCK:
pnpm add kbar Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
pnpm add kbar CODE_BLOCK:
pnpm add kbar CODE_BLOCK:
{ "dependencies": { "kbar": "^0.1.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "dependencies": { "kbar": "^0.1.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} CODE_BLOCK:
{ "dependencies": { "kbar": "^0.1.0", "react": "^18.0.0", "react-dom": "^18.0.0" }
} COMMAND_BLOCK:
// src/App.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar';
import './App.css'; // Define actions for the command palette
const actions = [ { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing words articles', perform: () => { console.log('Navigate to blog'); window.location.pathname = '/blog'; } }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message', perform: () => { console.log('Navigate to contact'); window.location.pathname = '/contact'; } }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => { window.open('https://github.com', '_blank'); } }
]; // Component to render search results
function RenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', opacity: 0.5 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#eee' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px' }} > <div style={{ display: 'flex', flexDirection: 'column' }}> <span>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> </div> ) } /> );
} // Main app component
function App() { return ( <KBarProvider actions={actions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch /> <RenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div className="App"> <h1>My Application</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> </div> </KBarProvider> );
} export default App; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/App.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar';
import './App.css'; // Define actions for the command palette
const actions = [ { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing words articles', perform: () => { console.log('Navigate to blog'); window.location.pathname = '/blog'; } }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message', perform: () => { console.log('Navigate to contact'); window.location.pathname = '/contact'; } }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => { window.open('https://github.com', '_blank'); } }
]; // Component to render search results
function RenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', opacity: 0.5 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#eee' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px' }} > <div style={{ display: 'flex', flexDirection: 'column' }}> <span>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> </div> ) } /> );
} // Main app component
function App() { return ( <KBarProvider actions={actions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch /> <RenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div className="App"> <h1>My Application</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> </div> </KBarProvider> );
} export default App; COMMAND_BLOCK:
// src/App.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar';
import './App.css'; // Define actions for the command palette
const actions = [ { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing words articles', perform: () => { console.log('Navigate to blog'); window.location.pathname = '/blog'; } }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message', perform: () => { console.log('Navigate to contact'); window.location.pathname = '/contact'; } }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => { window.open('https://github.com', '_blank'); } }
]; // Component to render search results
function RenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', opacity: 0.5 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#eee' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px' }} > <div style={{ display: 'flex', flexDirection: 'column' }}> <span>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> </div> ) } /> );
} // Main app component
function App() { return ( <KBarProvider actions={actions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch /> <RenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div className="App"> <h1>My Application</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> </div> </KBarProvider> );
} export default App; COMMAND_BLOCK:
// src/AdvancedCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const advancedActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page', perform: () => console.log('Navigate to home') }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }
]; function AdvancedRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', textTransform: 'uppercase', color: '#666', fontWeight: 600 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#f0f0f0' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px', borderLeft: active ? '3px solid #007bff' : '3px solid transparent' }} > {item.icon && <span style={{ fontSize: '20px' }}>{item.icon}</span>} <div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}> <span style={{ fontWeight: 500 }}>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#ddd', borderRadius: '4px', fontSize: '11px' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function AdvancedCommandPalette() { return ( <KBarProvider actions={advancedActions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch placeholder="Type a command or search..." /> <AdvancedRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px' }}> <h1>Advanced Command Palette</h1> <p>Press ⌘K to open</p> </div> </KBarProvider> );
} export default AdvancedCommandPalette; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/AdvancedCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const advancedActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page', perform: () => console.log('Navigate to home') }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }
]; function AdvancedRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', textTransform: 'uppercase', color: '#666', fontWeight: 600 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#f0f0f0' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px', borderLeft: active ? '3px solid #007bff' : '3px solid transparent' }} > {item.icon && <span style={{ fontSize: '20px' }}>{item.icon}</span>} <div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}> <span style={{ fontWeight: 500 }}>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#ddd', borderRadius: '4px', fontSize: '11px' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function AdvancedCommandPalette() { return ( <KBarProvider actions={advancedActions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch placeholder="Type a command or search..." /> <AdvancedRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px' }}> <h1>Advanced Command Palette</h1> <p>Press ⌘K to open</p> </div> </KBarProvider> );
} export default AdvancedCommandPalette; COMMAND_BLOCK:
// src/AdvancedCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const advancedActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page', perform: () => console.log('Navigate to home') }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }
]; function AdvancedRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 16px', fontSize: '12px', textTransform: 'uppercase', color: '#666', fontWeight: 600 }}> {item} </div> ) : ( <div style={{ padding: '12px 16px', background: active ? '#f0f0f0' : 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '12px', borderLeft: active ? '3px solid #007bff' : '3px solid transparent' }} > {item.icon && <span style={{ fontSize: '20px' }}>{item.icon}</span>} <div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}> <span style={{ fontWeight: 500 }}>{item.name}</span> {item.subtitle && ( <span style={{ fontSize: '12px', opacity: 0.6 }}> {item.subtitle} </span> )} </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#ddd', borderRadius: '4px', fontSize: '11px' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function AdvancedCommandPalette() { return ( <KBarProvider actions={advancedActions}> <KBarPortal> <KBarPositioner> <KBarAnimator> <KBarSearch placeholder="Type a command or search..." /> <AdvancedRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px' }}> <h1>Advanced Command Palette</h1> <p>Press ⌘K to open</p> </div> </KBarProvider> );
} export default AdvancedCommandPalette; COMMAND_BLOCK:
// src/ComprehensiveCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const comprehensiveActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page main', perform: () => console.log('Navigate to home'), icon: '🏠' }, { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing articles posts', perform: () => console.log('Navigate to blog'), icon: '📝' }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message reach', perform: () => console.log('Navigate to contact'), icon: '📧', subtitle: 'Get in touch with us' }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => window.open('https://github.com', '_blank'), icon: '🐙' }, { id: 'docs', name: 'Documentation', shortcut: ['d'], keywords: 'docs help guide', perform: () => window.open('https://docs.example.com', '_blank'), icon: '📚' }
]; function ComprehensiveRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} maxHeight={400} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 20px', fontSize: '11px', textTransform: 'uppercase', color: '#666', letterSpacing: '1px', fontWeight: 600, backgroundColor: '#f8f9fa' }}> {item} </div> ) : ( <div style={{ padding: '12px 20px', backgroundColor: active ? '#e7f3ff' : 'transparent', borderLeft: active ? '3px solid #007bff' : '3px solid transparent', display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', transition: 'all 0.2s ease' }} > <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}> {item.icon && ( <div style={{ fontSize: '20px', width: '24px', textAlign: 'center' }}> {item.icon} </div> )} <div> <div style={{ color: '#333', fontSize: '14px', fontWeight: 500 }}> {item.name} </div> {item.subtitle && ( <div style={{ color: '#666', fontSize: '12px', marginTop: '2px' }}> {item.subtitle} </div> )} </div> </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#f0f0f0', borderRadius: '4px', fontSize: '11px', color: '#666', fontFamily: 'monospace', border: '1px solid #ddd' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function ComprehensiveCommandPalette() { return ( <KBarProvider actions={comprehensiveActions}> <KBarPortal> <KBarPositioner style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)', zIndex: 9999 }} > <KBarAnimator style={{ maxWidth: '600px', width: '100%', backgroundColor: 'white', borderRadius: '12px', overflow: 'hidden', boxShadow: '0 16px 70px rgba(0, 0, 0, 0.3)' }} > <KBarSearch style={{ padding: '16px 20px', fontSize: '16px', width: '100%', boxSizing: 'border-box', outline: 'none', border: 'none', borderBottom: '1px solid #eee' }} placeholder="Type a command or search..." /> <ComprehensiveRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px', minHeight: '100vh' }}> <h1>Comprehensive Command Palette</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> <div style={{ marginTop: '20px' }}> <h2>Available Commands:</h2> <ul> <li><strong>h</strong> - Navigate to Home</li> <li><strong>b</strong> - Navigate to Blog</li> <li><strong>c</strong> - Navigate to Contact</li> <li><strong>s</strong> - Open Settings</li> <li><strong>t</strong> - Toggle Theme</li> <li><strong>g h</strong> - Open GitHub</li> <li><strong>d</strong> - Open Documentation</li> </ul> </div> </div> </KBarProvider> );
} export default ComprehensiveCommandPalette; Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
// src/ComprehensiveCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const comprehensiveActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page main', perform: () => console.log('Navigate to home'), icon: '🏠' }, { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing articles posts', perform: () => console.log('Navigate to blog'), icon: '📝' }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message reach', perform: () => console.log('Navigate to contact'), icon: '📧', subtitle: 'Get in touch with us' }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => window.open('https://github.com', '_blank'), icon: '🐙' }, { id: 'docs', name: 'Documentation', shortcut: ['d'], keywords: 'docs help guide', perform: () => window.open('https://docs.example.com', '_blank'), icon: '📚' }
]; function ComprehensiveRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} maxHeight={400} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 20px', fontSize: '11px', textTransform: 'uppercase', color: '#666', letterSpacing: '1px', fontWeight: 600, backgroundColor: '#f8f9fa' }}> {item} </div> ) : ( <div style={{ padding: '12px 20px', backgroundColor: active ? '#e7f3ff' : 'transparent', borderLeft: active ? '3px solid #007bff' : '3px solid transparent', display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', transition: 'all 0.2s ease' }} > <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}> {item.icon && ( <div style={{ fontSize: '20px', width: '24px', textAlign: 'center' }}> {item.icon} </div> )} <div> <div style={{ color: '#333', fontSize: '14px', fontWeight: 500 }}> {item.name} </div> {item.subtitle && ( <div style={{ color: '#666', fontSize: '12px', marginTop: '2px' }}> {item.subtitle} </div> )} </div> </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#f0f0f0', borderRadius: '4px', fontSize: '11px', color: '#666', fontFamily: 'monospace', border: '1px solid #ddd' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function ComprehensiveCommandPalette() { return ( <KBarProvider actions={comprehensiveActions}> <KBarPortal> <KBarPositioner style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)', zIndex: 9999 }} > <KBarAnimator style={{ maxWidth: '600px', width: '100%', backgroundColor: 'white', borderRadius: '12px', overflow: 'hidden', boxShadow: '0 16px 70px rgba(0, 0, 0, 0.3)' }} > <KBarSearch style={{ padding: '16px 20px', fontSize: '16px', width: '100%', boxSizing: 'border-box', outline: 'none', border: 'none', borderBottom: '1px solid #eee' }} placeholder="Type a command or search..." /> <ComprehensiveRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px', minHeight: '100vh' }}> <h1>Comprehensive Command Palette</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> <div style={{ marginTop: '20px' }}> <h2>Available Commands:</h2> <ul> <li><strong>h</strong> - Navigate to Home</li> <li><strong>b</strong> - Navigate to Blog</li> <li><strong>c</strong> - Navigate to Contact</li> <li><strong>s</strong> - Open Settings</li> <li><strong>t</strong> - Toggle Theme</li> <li><strong>g h</strong> - Open GitHub</li> <li><strong>d</strong> - Open Documentation</li> </ul> </div> </div> </KBarProvider> );
} export default ComprehensiveCommandPalette; COMMAND_BLOCK:
// src/ComprehensiveCommandPalette.jsx
import React from 'react';
import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch, KBarResults, useMatches
} from 'kbar'; const comprehensiveActions = [ { id: 'home', name: 'Home', shortcut: ['h'], keywords: 'home page main', perform: () => console.log('Navigate to home'), icon: '🏠' }, { id: 'blog', name: 'Blog', shortcut: ['b'], keywords: 'writing articles posts', perform: () => console.log('Navigate to blog'), icon: '📝' }, { id: 'contact', name: 'Contact', shortcut: ['c'], keywords: 'email message reach', perform: () => console.log('Navigate to contact'), icon: '📧', subtitle: 'Get in touch with us' }, { id: 'settings', name: 'Settings', shortcut: ['s'], keywords: 'preferences config', perform: () => console.log('Open settings'), icon: '⚙️', subtitle: 'Configure your preferences' }, { id: 'theme', name: 'Toggle Theme', shortcut: ['t'], keywords: 'dark light mode', perform: () => console.log('Toggle theme'), icon: '🌓' }, { id: 'github', name: 'Open GitHub', shortcut: ['g', 'h'], keywords: 'code repository', perform: () => window.open('https://github.com', '_blank'), icon: '🐙' }, { id: 'docs', name: 'Documentation', shortcut: ['d'], keywords: 'docs help guide', perform: () => window.open('https://docs.example.com', '_blank'), icon: '📚' }
]; function ComprehensiveRenderResults() { const { results } = useMatches(); return ( <KBarResults items={results} maxHeight={400} onRender={({ item, active }) => typeof item === 'string' ? ( <div style={{ padding: '8px 20px', fontSize: '11px', textTransform: 'uppercase', color: '#666', letterSpacing: '1px', fontWeight: 600, backgroundColor: '#f8f9fa' }}> {item} </div> ) : ( <div style={{ padding: '12px 20px', backgroundColor: active ? '#e7f3ff' : 'transparent', borderLeft: active ? '3px solid #007bff' : '3px solid transparent', display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', transition: 'all 0.2s ease' }} > <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}> {item.icon && ( <div style={{ fontSize: '20px', width: '24px', textAlign: 'center' }}> {item.icon} </div> )} <div> <div style={{ color: '#333', fontSize: '14px', fontWeight: 500 }}> {item.name} </div> {item.subtitle && ( <div style={{ color: '#666', fontSize: '12px', marginTop: '2px' }}> {item.subtitle} </div> )} </div> </div> {item.shortcut && ( <div style={{ display: 'flex', gap: '4px' }}> {item.shortcut.map((key) => ( <kbd key={key} style={{ padding: '4px 8px', backgroundColor: '#f0f0f0', borderRadius: '4px', fontSize: '11px', color: '#666', fontFamily: 'monospace', border: '1px solid #ddd' }} > {key} </kbd> ))} </div> )} </div> ) } /> );
} function ComprehensiveCommandPalette() { return ( <KBarProvider actions={comprehensiveActions}> <KBarPortal> <KBarPositioner style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)', zIndex: 9999 }} > <KBarAnimator style={{ maxWidth: '600px', width: '100%', backgroundColor: 'white', borderRadius: '12px', overflow: 'hidden', boxShadow: '0 16px 70px rgba(0, 0, 0, 0.3)' }} > <KBarSearch style={{ padding: '16px 20px', fontSize: '16px', width: '100%', boxSizing: 'border-box', outline: 'none', border: 'none', borderBottom: '1px solid #eee' }} placeholder="Type a command or search..." /> <ComprehensiveRenderResults /> </KBarAnimator> </KBarPositioner> </KBarPortal> <div style={{ padding: '40px', minHeight: '100vh' }}> <h1>Comprehensive Command Palette</h1> <p>Press ⌘K (or Ctrl+K) to open the command palette</p> <div style={{ marginTop: '20px' }}> <h2>Available Commands:</h2> <ul> <li><strong>h</strong> - Navigate to Home</li> <li><strong>b</strong> - Navigate to Blog</li> <li><strong>c</strong> - Navigate to Contact</li> <li><strong>s</strong> - Open Settings</li> <li><strong>t</strong> - Toggle Theme</li> <li><strong>g h</strong> - Open GitHub</li> <li><strong>d</strong> - Open Documentation</li> </ul> </div> </div> </KBarProvider> );
} export default ComprehensiveCommandPalette; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import ComprehensiveCommandPalette from './ComprehensiveCommandPalette';
import './App.css'; function App() { return ( <div className="App"> <ComprehensiveCommandPalette /> </div> );
} export default App; Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
// src/App.jsx
import React from 'react';
import ComprehensiveCommandPalette from './ComprehensiveCommandPalette';
import './App.css'; function App() { return ( <div className="App"> <ComprehensiveCommandPalette /> </div> );
} export default App; CODE_BLOCK:
// src/App.jsx
import React from 'react';
import ComprehensiveCommandPalette from './ComprehensiveCommandPalette';
import './App.css'; function App() { return ( <div className="App"> <ComprehensiveCommandPalette /> </div> );
} export default App; - Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Basic knowledge of React hooks (useState, useEffect)
- Familiarity with JavaScript/TypeScript
- Understanding of keyboard shortcuts - KBarProvider: Context provider that wraps your app
- KBarPortal: Portal for rendering the command palette
- KBarPositioner: Positions the palette on screen
- KBarAnimator: Animates the palette appearance
- KBarSearch: Search input field
- KBarResults: Displays filtered results
- useMatches: Hook to get filtered results - Actions: Array of command objects with id, name, shortcut, keywords, and perform function
- Keyboard shortcuts: Press ⌘K (Mac) or Ctrl+K (Windows/Linux) to open
- Search: Automatically filters actions based on name and keywords
- Custom rendering: Use onRender prop to customize result appearance - Multiple actions with icons
- Keyboard shortcuts display
- Grouped results
- Custom styling
- Search functionality
- Action execution
- Responsive design - Command palette not opening: Make sure you've wrapped your app with KBarProvider. The default shortcut is ⌘K (Mac) or Ctrl+K (Windows/Linux). Check browser console for errors.
- Actions not showing: Verify that your actions array is properly formatted with required fields (id, name, perform). Check that KBarResults is inside KBarAnimator.
- Search not working: Ensure KBarSearch is included and useMatches hook is used correctly. Actions are filtered by name and keywords automatically.
- Styling issues: kbar is unstyled by default. Add custom styles to KBarPositioner, KBarAnimator, and result items. Use inline styles or CSS classes.
- Keyboard shortcuts not working: Check that no other components are intercepting keyboard events. Ensure KBarProvider is at the root level of your app.
- Portal rendering issues: Make sure KBarPortal is included. The portal renders the command palette outside the normal DOM hierarchy. - Explore action groups and nested actions
- Learn about custom action handlers
- Implement dynamic actions based on app state
- Add animations and transitions
- Create context-aware commands
- Integrate with routing libraries
- Check the official repository: https://github.com/timc1/kbar
how-totutorialguidedev.toailinuxroutingnodejavascriptgitgithub