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.
Prerequisites
Before you begin, make sure you have:
- 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
Installation
Install kbar using your preferred package manager:
npm install kbar
Or with yarn:
yarn add kbar
Or with pnpm:
pnpm add kbar
After installation, your package.json should include:
{
"dependencies": {
"kbar": "^0.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
kbar requires wrapping your application with KBarProvider and including the UI components. Let's set up the basic structure.
First Example / Basic Usage
Let's create a simple command palette. Update your src/App.jsx:
// 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;
This creates a basic command palette that opens with ⌘K (or Ctrl+K) and displays searchable actions.
Understanding the Basics
kbar provides command palette components:
- 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
Key concepts:
- 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
onRenderprop to customize result appearance
Here's an example with more features:
// 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;
Practical Example / Building Something Real
Let's build a comprehensive command palette with grouped actions and navigation:
// 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;
Update your App.jsx:
// 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;
This example demonstrates:
- Multiple actions with icons
- Keyboard shortcuts display
- Grouped results
- Custom styling
- Search functionality
- Action execution
- Responsive design
Common Issues / Troubleshooting
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
KBarResultsis insideKBarAnimator.Search not working: Ensure
KBarSearchis included anduseMatcheshook 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
KBarProvideris at the root level of your app.Portal rendering issues: Make sure
KBarPortalis included. The portal renders the command palette outside the normal DOM hierarchy.
Next Steps
Now that you have an understanding of kbar:
- 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
Summary
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.
SEO Keywords
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

Top comments (0)