Using Tailwind
Slash Command
Using Tailwind
Slash Command
Create a slash command to insert content into the editor.
Define suggestions
We export a helper to define the suggestions that will be shown in the command palette. createSuggestionItems
Copy
import {
CheckSquare,
Code,
Heading1,
Heading2,
Heading3,
List,
ListOrdered,
MessageSquarePlus,
Text,
TextQuote,
} from "lucide-react";
import { createSuggestionItems } from "novel/extensions";
import { startImageUpload } from "novel/plugins";
import { Command, renderItems } from "novel/extensions";
export const suggestionItems = createSuggestionItems([
{
title: "Send Feedback",
description: "Let us know how we can improve.",
icon: <MessageSquarePlus size={18} />,
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).run();
window.open("/feedback", "_blank");
},
},
{
title: "Text",
description: "Just start typing with plain text.",
searchTerms: ["p", "paragraph"],
icon: <Text size={18} />,
command: ({ editor, range }) => {
editor
.chain()
.focus()
.deleteRange(range)
.toggleNode("paragraph", "paragraph")
.run();
},
},
{
title: "To-do List",
description: "Track tasks with a to-do list.",
searchTerms: ["todo", "task", "list", "check", "checkbox"],
icon: <CheckSquare size={18} />,
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).toggleTaskList().run();
},
},
{
title: "Heading 1",
description: "Big section heading.",
searchTerms: ["title", "big", "large"],
icon: <Heading1 size={18} />,
command: ({ editor, range }) => {
editor
.chain()
.focus()
.deleteRange(range)
.setNode("heading", { level: 1 })
.run();
},
},
{
title: "Heading 2",
description: "Medium section heading.",
searchTerms: ["subtitle", "medium"],
icon: <Heading2 size={18} />,
command: ({ editor, range }) => {
editor
.chain()
.focus()
.deleteRange(range)
.setNode("heading", { level: 2 })
.run();
},
},
{
title: "Heading 3",
description: "Small section heading.",
searchTerms: ["subtitle", "small"],
icon: <Heading3 size={18} />,
command: ({ editor, range }) => {
editor
.chain()
.focus()
.deleteRange(range)
.setNode("heading", { level: 3 })
.run();
},
},
{
title: "Bullet List",
description: "Create a simple bullet list.",
searchTerms: ["unordered", "point"],
icon: <List size={18} />,
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).toggleBulletList().run();
},
},
{
title: "Numbered List",
description: "Create a list with numbering.",
searchTerms: ["ordered"],
icon: <ListOrdered size={18} />,
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).toggleOrderedList().run();
},
},
{
title: "Quote",
description: "Capture a quote.",
searchTerms: ["blockquote"],
icon: <TextQuote size={18} />,
command: ({ editor, range }) =>
editor
.chain()
.focus()
.deleteRange(range)
.toggleNode("paragraph", "paragraph")
.toggleBlockquote()
.run(),
},
{
title: "Code",
description: "Capture a code snippet.",
searchTerms: ["codeblock"],
icon: <Code size={18} />,
command: ({ editor, range }) =>
editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
},
]);
export const slashCommand = Command.configure({
suggestion: {
items: () => suggestionItems,
render: renderItems,
},
});
Register the command
We need to add the command to the extensions array
Copy
const extensions = [...defaultExtensions, slashCommand];
<EditorContent
extensions={extensions}
...
/>;
Create UI for the command
We map the suggestionItems and use the EditorCommand
and EditorCommandItem
components to create the UI for the command palette.
Components are wrapper over cmdk
Copy
...
<EditorContent>
<EditorCommand className='z-50 h-auto max-h-[330px] w-72 overflow-y-auto rounded-md border border-muted bg-background px-1 py-2 shadow-md transition-all'>
<EditorCommandEmpty className='px-2 text-muted-foreground'>No results</EditorCommandEmpty>
<EditorCommandList>
{suggestionItems.map((item) => (
<EditorCommandItem
value={item.title}
onCommand={(val) => item.command(val)}
className={`flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-accent aria-selected:bg-accent `}
key={item.title}>
<div className='flex h-10 w-10 items-center justify-center rounded-md border border-muted bg-background'>
{item.icon}
</div>
<div>
<p className='font-medium'>{item.title}</p>
<p className='text-xs text-muted-foreground'>{item.description}</p>
</div>
</EditorCommandItem>
))}
</EditorCommandList>
</EditorCommand>
</EditorContent>
...