Components
Block Context Menu
Block Context Menu
Display a context menu for blocks.
Installation
npx @udecode/plate-ui@latest add block-context-menu
Examples
import { useCallback, useState } from 'react';
import { AIChatPlugin } from '@udecode/plate-ai/react';
import { BlockquotePlugin } from '@udecode/plate-block-quote/react';
import { ParagraphPlugin, useEditorPlugin } from '@udecode/plate-core/react';
import { HEADING_KEYS } from '@udecode/plate-heading';
import { IndentListPlugin } from '@udecode/plate-indent-list/react';
import {
BLOCK_CONTEXT_MENU_ID,
BlockMenuPlugin,
BlockSelectionPlugin,
} from '@udecode/plate-selection/react';
import { unsetNodes } from '@udecode/slate';
import { focusEditor } from '@udecode/slate-react';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from './context-menu';
type Value = 'askAI' | null;
export function BlockContextMenu({ children }: { children: React.ReactNode }) {
const { api, editor } = useEditorPlugin(BlockMenuPlugin);
const [value, setValue] = useState<Value>(null);
const handleTurnInto = useCallback(
(type: string) => {
editor
.getApi(BlockSelectionPlugin)
.blockSelection.getNodes()
.forEach(([node, path]) => {
if (node[IndentListPlugin.key]) {
unsetNodes(editor, [IndentListPlugin.key, 'indent'], { at: path });
}
editor.tf.toggle.block({ type }, { at: path });
});
},
[editor]
);
const handleAlign = useCallback(
(align: 'center' | 'left' | 'right') => {
editor
.getTransforms(BlockSelectionPlugin)
.blockSelection.setNodes({ align });
},
[editor]
);
return (
<ContextMenu modal={false}>
<ContextMenuTrigger
onContextMenu={(event) => {
const dataset = (event.target as HTMLElement).dataset;
const disabled = dataset?.slateEditor === 'true';
if (disabled) return event.preventDefault();
api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {
x: event.clientX,
y: event.clientY,
});
}}
>
{children}
</ContextMenuTrigger>
<ContextMenuContent
className="w-64"
onCloseAutoFocus={(e) => {
e.preventDefault();
if (value === 'askAI') {
editor.getApi(AIChatPlugin).aiChat.show();
}
setValue(null);
}}
>
<ContextMenuItem
onClick={() => {
setValue('askAI');
}}
>
Ask AI
</ContextMenuItem>
<ContextMenuItem
onClick={() => {
editor
.getTransforms(BlockSelectionPlugin)
.blockSelection.removeNodes();
focusEditor(editor);
}}
>
Delete
</ContextMenuItem>
<ContextMenuItem
onClick={() => {
editor
.getTransforms(BlockSelectionPlugin)
.blockSelection.duplicate(
editor.getApi(BlockSelectionPlugin).blockSelection.getNodes()
);
}}
>
Duplicate
<ContextMenuShortcut>⌘ + D</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-48">
<ContextMenuItem
onClick={() => handleTurnInto(ParagraphPlugin.key)}
>
Paragraph
</ContextMenuItem>
<ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h1)}>
Heading 1
</ContextMenuItem>
<ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h2)}>
Heading 2
</ContextMenuItem>
<ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h3)}>
Heading 3
</ContextMenuItem>
<ContextMenuItem
onClick={() => handleTurnInto(BlockquotePlugin.key)}
>
Blockquote
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuItem
onClick={() =>
editor
.getTransforms(BlockSelectionPlugin)
.blockSelection.setIndent(1)
}
>
Indent
</ContextMenuItem>
<ContextMenuItem
onClick={() =>
editor
.getTransforms(BlockSelectionPlugin)
.blockSelection.setIndent(-1)
}
>
Outdent
</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>Align</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-48">
<ContextMenuItem onClick={() => handleAlign('left')}>
Left
</ContextMenuItem>
<ContextMenuItem onClick={() => handleAlign('center')}>
Center
</ContextMenuItem>
<ContextMenuItem onClick={() => handleAlign('right')}>
Right
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
</ContextMenuContent>
</ContextMenu>
);
}
Plus
In Plate Plus, We have provided a more advanced menu.
- More advanced menu items.
- Supports search functionality and carefully designed shortcuts.
- More refined styles and animations.
- You can open this menu in various ways, such as through the drag button.
Build your editor even faster
Complete, deployable AI-powered template with backend.
All components included.
Customizable and extensible.
Get all-accessCustomizable and extensible.