- Created a new document for using components in Milkdown. - Added a guide for using plugins in Milkdown, including toggling plugins programmatically and listing official plugins. - Introduced a recipe for integrating Milkdown with Angular, including installation steps and component creation. - Added a recipe for using Milkdown with Next.js, detailing installation and component setup. - Created a guide for integrating Milkdown with NuxtJS, including installation and component creation. - Added a comprehensive guide for using Milkdown with React, covering both Crepe and core Milkdown usage. - Introduced a recipe for SolidJS integration with Milkdown, including installation and component creation. - Added a guide for using Milkdown with Svelte, detailing installation and component setup. - Created a comprehensive guide for integrating Milkdown with Vue, covering both Crepe and core Milkdown usage. - Added a recipe for using Milkdown with Vue2, including installation and component creation.
4.9 KiB
Understanding Headless Slash Plugin
In the old Milkdown versions. The slash plugin can be used to display a list of commands when users type / in the editor.
It provides a way to insert nodes and commands into the editor, and it's really easy to use.
However, it's hard to extend the slash plugin to support more commands, or if you want to change the UI of the slash plugin, you have to rewrite the whole plugin. But, write a new plugin is always a hard work. You have to understand a lot of context and APIs of both ProseMirror and Milkdown.
User Story
So, why don't we provide the slash plugin as a headless plugin? In most cases, developers just want to make sure that when users type a special character, a dropdown menu will be displayed. But the trigger character and the UI of the dropdown menu are different in different cases.
For example:
- When user type
/, the menu contains a list of commands. - When user type
:, the menu contains a list of emoji. - When user type
@, the menu contains a list of users.
That's the story behind the headless slash plugin. We provide the plugin to solve a single problem: display a dropdown menu when users input satisfy a condition.
How to use
In the new slash plugin, you'll need to control when to display the dropdown menu by yourself.
And you'll also need to provide the UI of the dropdown menu.
So, you'll need to create a SlashProvider instance.
import { slashPlugin, SlashProvider } from "@milkdown/plugin-slash";
const slashProvider = new SlashProvider({
content: YourDropdownUI,
shouldShow(this: SlashProvider, view: EditorView) {
const currentText = this.getContent(view);
if (currentText === "") {
return false;
}
// Display the menu if the last character is `/`.
if (currentText.endsWith("/")) {
return true;
}
return false;
},
});
Then, you can use the slash provider in your plugin view.
import { EditorState } from "@milkdown/prose/state";
import { EditorView, PluginView } from "@milkdown/prose/view";
function yourSlashView(): PluginView {
return {
update: (view: EditorView, prevState: EditorState) => {
slashProvider.update(view, prevState);
},
destroy: () => {
slashProvider.destroy();
},
};
}
Last, you'll need to add the slash plugin to your editor.
import { Editor } from "@milkdown/core";
import { slashFactory } from "@milkdown/plugin-slash";
const slash = slashFactory("my-slash");
Editor.make()
.config((ctx) => {
ctx.set(slash.key, {
view: slashPluginView,
});
})
.use(slash)
.create();
Use with Prosemirror Adapter
If you're using milkdown with UI frameworks like React, I recommend you to use the Prosemirror Adapter. It can help you build prosemirror UI components with your favorite UI framework.
For example, if you're using React:
import { SlashProvider } from "@milkdown/plugin-slash";
import { useInstance } from "@milkdown/react";
import { usePluginViewContext } from "@prosemirror-adapter/react";
export const DropdownMenu = () => {
const { view, prevState } = usePluginViewContext();
const slashProvider = useRef<SlashProvider>();
const divRef = useRef<HTMLDivElement>(null);
const [loading] = useInstance();
useEffect(() => {
if (!ref.current || loading) return;
slashProvider.current ??= new SlashProvider({
content: divRef.current,
// ...
});
return () => {
slashProvider.current?.destroy();
slashProvider.current = undefined;
};
}, [loading, root, setOpened, setSearch, setSelected]);
useEffect(() => {
slashProvider.current?.update(view, prevState);
});
// Add a wrapper `div` to hide the dropdown menu when initializing.
return (
<div className="hidden">
<div role="tooltip" ref={divRef}>
<h1>Hi! I'm a dropdown menu.</h1>
</div>
</div>
);
};
And in your editor component:
import { usePluginViewFactory } from "@prosemirror-adapter/react";
export const YourEditor = () => {
const pluginViewFactory = usePluginViewFactory();
useEditor((editor) => {
return Editor.make()
.config((ctx) => {
ctx.set(slash.key, {
view: pluginViewFactory({
component: DopdownMenu,
}),
});
})
.use(slash);
});
// ...
};
Real World Example
In milkdown playground, you can type / to display a dropdown menu.
You can also type :(\S)+ (for example: :mil) to display a list of emojis.
You can find the source code of them in Milkdown website. I hope you enjoy the new slash plugin.


