- 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.4 KiB
Example: Slash Plugin
After reading the tooltip guide you already know how Milkdown separates positioning logic (provider) from editor wiring (ctx slices produced by a factory).
The @milkdown/plugin-slash package applies exactly the same idea but focuses on command palettes triggered by a character – familiar to / menus in modern editors.
This document shows you how to:
- Understand what the slash plugin gives you out-of-the-box.
- Build a vanilla TypeScript implementation of a basic
/menu. - Use the slash provider with React and Vue.
- Explore a full-blown menu feature that ships inside Milkdown's Crepe UI.
1. Anatomy of a Slash Plugin
@milkdown/plugin-slash exports two utilities:
SlashProvider– Measures the caret position and manages show / hide of your menu.slashFactory(id)– Generates a ctx slice & ProseMirror plugin pair that plugs the provider into the editor.
import { slashFactory } from "@milkdown/plugin-slash";
export const [mySlashSpec, mySlashPlugin] = slashFactory("my");
Just like the tooltip factory:
mySlashSpecis where you put aPluginSpec(what ProseMirror needs).mySlashPluginturns that spec into a runtime plugin.
2. A Minimal Vanilla / Menu
Below we create a small menu that suggests two commands whenever the user types /.
import { SlashProvider, slashFactory } from "@milkdown/plugin-slash";
import { Editor } from "@milkdown/kit/core";
import { commonmark } from "@milkdown/kit/preset/commonmark";
// DOM content of the menu – plain HTML for the demo
const menu = document.createElement("div");
menu.className = "slash-menu";
menu.style.cssText = `
position:absolute;padding:4px 0;background:white;border:1px solid #eee;
box-shadow:0 2px 8px rgba(0,0,0,.15);border-radius:6px;font-size:14px;
`;
menu.innerHTML = `<ul style="margin:0;padding:0;list-style:none">
<li data-cmd="h1" style="padding:4px 12px;cursor:pointer">Heading 1</li>
<li data-cmd="bullet" style="padding:4px 12px;cursor:pointer">Bullet List</li>
</ul>`;
// Click handler – replace with real commands
menu.addEventListener("click", (e) => {
const target = e.target as HTMLElement;
const cmd = target.dataset.cmd;
alert(`Run command: ${cmd}`);
});
// Provider positions & shows above DOM element
const provider = new SlashProvider({
content: menu,
// show the menu when the last character before caret is '/'
shouldShow(view) {
return provider.getContent(view)?.endsWith("/") ?? false;
},
offset: 8,
});
const slash = slashFactory("demo");
const slashConfig = (ctx: Ctx) => {
ctx.set(slash.key, {
view: () => ({
update: provider.update,
destroy: provider.destroy,
}),
});
};
Editor.make().config(slashConfig).use(commonmark).use(slash).create();
Key takeaways:
SlashProviderhas a helpergetContent(view)to fetch text before the caret – handy for filtering.- You decide when to show the menu via the
shouldShowcallback (default: when last char is/). - The provider only manipulates position + visibility; rendering & commands are completely yours.
3. Framework Examples
React
::iframe{src="https://stackblitz.com/github/Milkdown/examples/tree/main/react-slash"}
Highlights:
- A
<SlashMenu/>React component renders the list. - The component root is passed to
SlashProvider(just like the tooltip demo). - React hooks manage internal focus & keyboard navigation.
Vue
::iframe{src="https://stackblitz.com/github/Milkdown/examples/tree/main/vue-slash"}
The Vue version uses Teleport to append the menu to document.body and ref / watch for reactivity.
4. Real-world Feature – Crepe Block Menu
Milkdown's Crepe UI implements an extensible block-level menu on top of the slash plugin. You'll find the source code at:
packages/crepe/src/feature/block-edit/menu/
Notable patterns to look for:
- Context slices (
menu/menuAPI) to expose imperativeshow&hidemethods. - Filtering commands based on the current text after
/. - Preventing the menu inside
codeblocks or lists.
Studying this folder is a great next step once you master the basics.
5. Summary & Next Steps
@milkdown/plugin-slashgives you caret detection + positioning – nothing else.- UI, behaviour, and commands are fully customisable.
Fork one of the examples above, add your own commands, and you'll have a modern / command palette in minutes ✨.