The SlashCommandMenu component provides a command palette interface that appears when users type /. It allows quick insertion of blocks by browsing or searching available plugin types.
Installation
Basic Usage
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import { SlashCommandMenu } from '@yoopta/ui';
import { useMemo } from 'react';
function MyEditor() {
const editor = useMemo(() => createYooptaEditor({ plugins }), []);
return (
<YooptaEditor editor={editor}>
<SlashCommandMenu>
{({ items }) => (
<SlashCommandMenu.Content>
<SlashCommandMenu.List>
<SlashCommandMenu.Empty>No blocks found</SlashCommandMenu.Empty>
{items.map((item) => (
<SlashCommandMenu.Item
key={item.id}
value={item.id}
title={item.title}
description={item.description}
icon={item.icon}
/>
))}
</SlashCommandMenu.List>
<SlashCommandMenu.Footer />
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
</YooptaEditor>
);
}
Component API
SlashCommandMenu (Root)
The root component that manages command menu state and positioning.
children
ReactNode | ((props: SlashCommandRootChildrenProps) => ReactNode)
required
Menu content or render function receiving grouped items
Custom items to display. If not provided, uses plugins from editor
Character that triggers the menu
onSelect
(item: SlashCommandItem) => void
Called when an item is selected
Additional CSS class name
SlashCommandMenu.Content
The floating content container.
Additional CSS class name
SlashCommandMenu.List
Scrollable list container for menu items.
Additional CSS class name
SlashCommandMenu.Item
Unique identifier (typically plugin type)
Additional search keywords
Whether the item is disabled
SlashCommandMenu.Group
Groups related items together.
SlashCommandMenu.Empty
Displayed when no items match the search.
children
ReactNode
default:"No results found"
Empty state content
SlashCommandMenu.Separator
Visual separator between items or groups.
Footer section (typically shows keyboard hints).
Examples
With Custom Icons
import { SlashCommandMenu } from '@yoopta/ui';
import {
Heading1,
List,
Image,
Code,
Quote
} from 'lucide-react';
const ICON_MAP = {
HeadingOne: Heading1,
BulletedList: List,
Image: Image,
Code: Code,
Blockquote: Quote,
};
function CustomIconMenu() {
return (
<SlashCommandMenu>
{({ items }) => (
<SlashCommandMenu.Content>
<SlashCommandMenu.List>
<SlashCommandMenu.Empty>No blocks found</SlashCommandMenu.Empty>
{items.map((item) => {
const Icon = ICON_MAP[item.id];
return (
<SlashCommandMenu.Item
key={item.id}
value={item.id}
title={item.title}
description={item.description}
icon={Icon ? <Icon size={20} /> : null}
/>
);
})}
</SlashCommandMenu.List>
<SlashCommandMenu.Footer />
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
);
}
Grouped Items
import { SlashCommandMenu } from '@yoopta/ui';
function GroupedMenu() {
return (
<SlashCommandMenu>
{({ groupedItems }) => (
<SlashCommandMenu.Content>
<SlashCommandMenu.List>
<SlashCommandMenu.Empty>No blocks found</SlashCommandMenu.Empty>
{Array.from(groupedItems.entries()).map(([group, items]) => (
<SlashCommandMenu.Group key={group} heading={group}>
{items.map((item) => (
<SlashCommandMenu.Item
key={item.id}
value={item.id}
title={item.title}
description={item.description}
icon={item.icon}
/>
))}
</SlashCommandMenu.Group>
))}
</SlashCommandMenu.List>
<SlashCommandMenu.Footer />
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
);
}
Custom Items
import { SlashCommandMenu } from '@yoopta/ui';
import type { SlashCommandItemType } from '@yoopta/ui';
import { Zap, Star } from 'lucide-react';
const CUSTOM_ITEMS: SlashCommandItemType[] = [
{
id: 'ai-complete',
title: 'AI Complete',
description: 'Complete text with AI',
icon: <Zap />,
group: 'AI',
keywords: ['ai', 'complete', 'generate'],
onSelect: () => {
// Custom AI completion logic
},
},
{
id: 'featured-callout',
title: 'Featured Callout',
description: 'Special highlighted callout',
icon: <Star />,
group: 'Content',
},
];
function CustomItemsMenu() {
return (
<SlashCommandMenu items={CUSTOM_ITEMS}>
{({ items }) => (
<SlashCommandMenu.Content>
<SlashCommandMenu.List>
{items.map((item) => (
<SlashCommandMenu.Item
key={item.id}
value={item.id}
title={item.title}
description={item.description}
icon={item.icon}
/>
))}
</SlashCommandMenu.List>
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
);
}
import { SlashCommandMenu } from '@yoopta/ui';
function MenuWithCustomFooter() {
return (
<SlashCommandMenu>
{({ items }) => (
<SlashCommandMenu.Content>
<SlashCommandMenu.List>
{items.map((item) => (
<SlashCommandMenu.Item key={item.id} {...item} />
))}
</SlashCommandMenu.List>
<SlashCommandMenu.Footer>
<div style={{ padding: '8px', fontSize: '12px', color: '#666' }}>
↑↓ Navigate • ↵ Select • Esc Close
</div>
</SlashCommandMenu.Footer>
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
);
}
Custom Trigger
import { SlashCommandMenu } from '@yoopta/ui';
function CustomTriggerMenu() {
return (
<SlashCommandMenu trigger="@">
{/* Menu content */}
</SlashCommandMenu>
);
}
Behavior
Trigger Detection
The menu automatically:
- Opens when trigger character is typed
- Filters items based on typed text after trigger
- Closes on escape, selection, or clicking outside
- Handles keyboard navigation (arrow keys, enter)
Search
Searches across:
- Item title
- Item description
- Custom keywords
Fuzzy matching supported for better UX.
Keyboard Navigation
↑ / ↓ - Navigate items
Enter - Select highlighted item
Escape - Close menu
- Type to filter
Selection Behavior
When an item is selected:
- Trigger character and search text are removed
- New block is inserted at current position
- Focus moves to the new block
- Menu closes
Item Type
type SlashCommandItem = {
id: string; // Unique identifier (plugin type)
title: string; // Display title
description?: string; // Optional description
icon?: ReactNode; // Optional icon
keywords?: string[]; // Search keywords
group?: string; // Group name for grouping
disabled?: boolean; // Disable selection
onSelect?: () => void; // Custom select handler
};
Styling
CSS Classes
.yoopta-ui-slash-command-root {
/* Menu container */
}
.yoopta-ui-slash-command-content {
/* Content wrapper */
}
.yoopta-ui-slash-command-list {
/* Scrollable list */
}
.yoopta-ui-slash-command-item {
/* Menu item */
}
.yoopta-ui-slash-command-item[data-selected="true"] {
/* Selected item */
}
.yoopta-ui-slash-command-group {
/* Group container */
}
.yoopta-ui-slash-command-footer {
/* Footer section */
}
Custom Styling
<SlashCommandMenu className="my-menu">
{({ items }) => (
<SlashCommandMenu.Content className="my-content">
<SlashCommandMenu.List className="my-list">
{items.map((item) => (
<SlashCommandMenu.Item
key={item.id}
{...item}
className="my-item"
/>
))}
</SlashCommandMenu.List>
</SlashCommandMenu.Content>
)}
</SlashCommandMenu>
TypeScript
import type {
SlashCommandItemType,
SlashCommandGroupType,
SlashCommandRootProps,
SlashCommandContentProps,
SlashCommandListProps,
SlashCommandItemProps,
SlashCommandGroupProps,
} from '@yoopta/ui';
See Also