### Runtime Editor Commands with action()
Source: https://context7.com/milkdown/examples/llms.txt
Demonstrates using the `editor.action()` API to interact with the Milkdown editor at runtime. This includes getting markdown, focusing the editor, and replacing content. Ensure the necessary HTML elements with corresponding IDs exist for the event listeners.
```typescript
import { defaultValueCtx, Editor, editorViewCtx, rootCtx, serializerCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import '@milkdown/theme-nord/style.css';
const markdown = `# Editor Actions
Use actions to interact with the editor programmatically.`;
const editor = await Editor.make()
.config((ctx) => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
.create();
// Get current markdown content
document.getElementById('get-markdown')?.addEventListener('click', () => {
editor.action((ctx) => {
const view = ctx.get(editorViewCtx);
const serializer = ctx.get(serializerCtx);
const markdown = serializer(view.state.doc);
console.log('Current markdown:', markdown);
});
});
// Focus the editor
document.getElementById('focus-editor')?.addEventListener('click', () => {
editor.action((ctx) => {
const view = ctx.get(editorViewCtx);
view.focus();
});
});
// Replace content
document.getElementById('replace-content')?.addEventListener('click', () => {
editor.action((ctx) => {
const view = ctx.get(editorViewCtx);
const { state } = view;
const tr = state.tr.insertText('New content inserted!', 0, state.doc.content.size);
view.dispatch(tr);
});
});
```
--------------------------------
### Async ProseMirror Plugin for Shiki Syntax Highlighting
Source: https://context7.com/milkdown/examples/llms.txt
Implement an asynchronous ProseMirror plugin using $proseAsync to enable syntax highlighting for code blocks with Shiki. Ensure Shiki is installed and configured with desired themes and languages.
```typescript
import { defaultValueCtx, Editor, rootCtx } from "@milkdown/kit/core";
import { commonmark, codeBlockSchema } from "@milkdown/kit/preset/commonmark";
import { nord } from "@milkdown/theme-nord";
import { $proseAsync } from "@milkdown/kit/utils";
import { Plugin, PluginKey } from "@milkdown/kit/prose/state";
import { Decoration, DecorationSet } from "@milkdown/kit/prose/view";
import { findChildren } from "@milkdown/kit/prose";
import { createHighlighter, type Highlighter } from "shiki";
import type { Node } from "@milkdown/kit/prose/model";
import type { Ctx } from "@milkdown/kit/ctx";
import "@milkdown/theme-nord/style.css";
const markdown = `# Shiki Syntax Highlighting
\`\`\`typescript
interface User {
name: string;
email: string;
}
const greet = (user: User): string => {
return \
Hello, ${user.name}!
};
\`\`\`
`;
// Create decorations for syntax highlighting
function getDecorations(ctx: Ctx, doc: Node, highlighter: Highlighter) {
const decorations: Decoration[] = [];
const codeBlocks = findChildren(
(node) => node.type === codeBlockSchema.type(ctx)
)(doc);
codeBlocks.forEach((block) => {
let from = block.pos + 1;
const { language } = block.node.attrs;
if (!language) return;
const { tokens } = highlighter.codeToTokens(block.node.textContent, {
lang: language,
theme: 'github-light',
});
for (const line of tokens) {
for (const token of line) {
const to = from + token.content.length;
decorations.push(
Decoration.inline(from, to, {
style: `color: ${token.color}`,
class: 'shiki-token',
})
);
from = to;
}
from += 1; // newline
}
});
return DecorationSet.create(doc, decorations);
}
// Async plugin for Shiki highlighting
const shikiPlugin = $proseAsync(async (ctx) => {
const key = new PluginKey("shiki");
const highlighter = await createHighlighter({
themes: ["github-light"],
langs: ["typescript", "javascript", "tsx", "jsx"],
});
return new Plugin({
key,
state: {
init: (_, { doc }) => getDecorations(ctx, doc, highlighter),
apply: (tr, value) => {
if (tr.docChanged) {
return getDecorations(ctx, tr.doc, highlighter);
}
return value.map(tr.mapping, tr.doc);
},
},
props: {
decorations: (state) => key.getState(state),
},
});
});
Editor.make()
.config((ctx) => {
ctx.set(rootCtx, "#app");
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(shikiPlugin)
.use(commonmark)
.create();
```
--------------------------------
### Enable Real-time Collaboration with Collab Plugin
Source: https://context7.com/milkdown/examples/llms.txt
Integrates the collab plugin with Yjs for real-time collaborative editing. This example sets up a WebSocket provider for synchronization and configures user awareness.
```typescript
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { collab, CollabService, collabServiceCtx } from '@milkdown/plugin-collab';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import { WebsocketProvider } from 'y-websocket';
import { Doc } from 'yjs';
import '@milkdown/theme-nord/style.css';
const markdown = `# Collaborative Document
> Edit together in real-time!
Multiple users can edit this document simultaneously.`;
const wsUrl = 'wss://demos.yjs.dev/ws'; // WebSocket server URL
const roomName = 'milkdown-room';
// Create the editor with collab plugin
const editor = await Editor.make()
.config((ctx) => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
.use(collab)
.create();
// Initialize collaboration after editor creation
editor.action((ctx) => {
const collabService = ctx.get(collabServiceCtx);
// Create Yjs document and WebSocket provider
const doc = new Doc();
const wsProvider = new WebsocketProvider(wsUrl, roomName, doc, {
connect: true
});
// Set user awareness (cursor, name, color)
wsProvider.awareness.setLocalStateField('user', {
name: 'User-' + Math.floor(Math.random() * 100),
color: '#' + Math.floor(Math.random() * 16777215).toString(16),
});
// Bind document and awareness to collab service
collabService.bindDoc(doc).setAwareness(wsProvider.awareness);
// Connect after sync
wsProvider.once('synced', (isSynced: boolean) => {
if (isSynced) {
collabService.applyTemplate(markdown).connect();
}
});
// Status updates
wsProvider.on('status', (event: { status: string }) => {
console.log('Connection status:', event.status);
});
});
```
--------------------------------
### Load Specific Features with CrepeBuilder
Source: https://context7.com/milkdown/examples/llms.txt
Use CrepeBuilder to selectively load only the necessary features for a smaller bundle size. This example enables only CodeMirror with Markdown language support.
```typescript
import { CrepeBuilder } from '@milkdown/crepe/builder';
import { codeMirror } from '@milkdown/crepe/feature/code-mirror';
import { LanguageDescription } from '@codemirror/language';
import { markdown as markdownLanguage } from '@codemirror/lang-markdown';
import { nord } from '@uiw/codemirror-theme-nord';
// Import only required CSS
import '@milkdown/crepe/theme/common/prosemirror.css';
import '@milkdown/crepe/theme/common/reset.css';
import '@milkdown/crepe/theme/common/code-mirror.css';
import '@milkdown/crepe/theme/nord-dark.css';
const markdown = `# Selective Features
\`\`\`markdown
# Only markdown language support enabled
\`\`\`
`;
new CrepeBuilder({
root: '#app',
defaultValue: markdown,
})
.addFeature(codeMirror, {
theme: nord,
languages: [
LanguageDescription.of({
name: "Markdown",
extensions: ["md", "markdown", "mkd"],
load() {
return Promise.resolve(markdownLanguage())
}
}),
]
})
.create();
```
--------------------------------
### Custom React Node Views for Blockquotes
Source: https://context7.com/milkdown/examples/llms.txt
Utilize the $view utility to replace default ProseMirror nodes with custom React components. This example shows how to render blockquotes using a custom styled React component.
```tsx
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react';
import { blockquoteSchema, commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import { useNodeViewFactory } from '@prosemirror-adapter/react';
import { $view } from '@milkdown/kit/utils';
import type { FC, ReactNode } from 'react';
import '@milkdown/theme-nord/style.css';
// Custom blockquote component
const CustomBlockquote: FC<{ children: ReactNode }> = ({ children }) => (
{children}
);
const markdown = `# Custom Node Views
> This blockquote is rendered with a custom React component!
Regular paragraph text here.`;
const MilkdownEditor: FC = () => {
const nodeViewFactory = useNodeViewFactory();
useEditor((root) => {
return Editor.make()
.config(ctx => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
// Replace blockquote with custom React component
.use($view(blockquoteSchema.node, () => nodeViewFactory({
component: CustomBlockquote
})))
}, [nodeViewFactory]);
return ;
};
const App: FC = () => (
);
```
--------------------------------
### Create Core Milkdown Editor Instance
Source: https://context7.com/milkdown/examples/llms.txt
Use Editor.make() for fundamental editor creation. Configure with .config(), add plugins with .use(), and initialize asynchronously with .create().
```typescript
import { defaultValueCtx, Editor, rootCtx } from "@milkdown/kit/core";
import { commonmark } from "@milkdown/kit/preset/commonmark";
import { nord } from "@milkdown/theme-nord";
import "@milkdown/theme-nord/style.css";
const markdown = `# Hello Milkdown
> A plugin-driven markdown editor framework.
This is a **bold** statement with *italic* text.`;
// Create and initialize the editor
const editor = await Editor.make()
.config((ctx) => {
// Set the DOM element to mount the editor
ctx.set(rootCtx, "#app");
// Set initial markdown content
ctx.set(defaultValueCtx, markdown);
})
.config(nord) // Apply Nord theme
.use(commonmark) // Enable commonmark syntax support
.create();
// Later: destroy the editor when done
// editor.destroy();
```
--------------------------------
### Crepe - Batteries-Included Editor Initialization
Source: https://context7.com/milkdown/examples/llms.txt
Initialize Crepe, a pre-configured Milkdown editor, for rapid prototyping. It includes common features out-of-the-box. Import necessary styles.
```typescript
import { Crepe } from '@milkdown/crepe';
import '@milkdown/crepe/theme/common/style.css';
import '@milkdown/crepe/theme/frame.css';
const markdown = `# Crepe Editor
> A fully-featured markdown editor.

**Crepe** includes:
- Rich text formatting
- Image blocks with captions
- Code blocks with syntax highlighting
- Tables and lists
- And much more!
\`\`\`typescript
const greeting = "Hello, Crepe!";
console.log(greeting);
\`\`\`
`;
const crepe = await new Crepe({
root: '#app',
defaultValue: markdown,
}).create();
// Access the underlying editor
// const editor = crepe.editor;
```
--------------------------------
### Integrate Crepe with React using useEditor
Source: https://context7.com/milkdown/examples/llms.txt
Demonstrates how to use the Crepe editor within a React application using the `useEditor` hook. Ensure MilkdownProvider is used to wrap the editor components.
```tsx
import type { FC } from "react";
import { Crepe } from "@milkdown/crepe";
import { Milkdown, MilkdownProvider, useEditor } from "@milkdown/react";
import "@milkdown/crepe/theme/common/style.css";
import "@milkdown/crepe/theme/frame.css";
const markdown = `# Crepe + React
> Full-featured editing in React.
This combines Crepe's features with React's ecosystem.`;
const CrepeEditor: FC = () => {
useEditor((root) => {
const crepe = new Crepe({
root,
defaultValue: markdown,
});
return crepe;
}, []);
return ;
};
const App: FC = () => (
);
```
--------------------------------
### Configure OpenAI API Key
Source: https://github.com/milkdown/examples/blob/main/vanilla-openai/README.md
Set the required environment variable for the OpenAI API key in the project root.
```bash
# notice that you need to replace the value with your own api key
VITE_OPENAPI_KEY=your_api_key
```
--------------------------------
### Implement Link Tooltip Plugin in TypeScript
Source: https://context7.com/milkdown/examples/llms.txt
Configures the link tooltip component and provides a helper function to trigger link insertion via the editor API.
```typescript
import { defaultValueCtx, Editor, editorViewCtx, rootCtx } from '@milkdown/kit/core';
import { commonmark, linkSchema } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import {
configureLinkTooltip,
linkTooltipPlugin,
linkTooltipAPI,
linkTooltipState
} from '@milkdown/kit/component/link-tooltip';
import type { Ctx } from '@milkdown/kit/ctx';
import '@milkdown/theme-nord/style.css';
const markdown = `# Link Tooltip Component
Select text and click the link button to add links.
Visit [Milkdown](https://milkdown.dev) for documentation.`;
// Function to insert a link on selected text
const insertLink = (ctx: Ctx) => {
const view = ctx.get(editorViewCtx);
const { selection, doc } = view.state;
// Must have text selected
if (selection.empty) return;
// Don't re-enter edit mode
if (ctx.get(linkTooltipState.key).mode === 'edit') return;
// Check if selection already has a link
const hasLink = doc.rangeHasMark(
selection.from,
selection.to,
linkSchema.type(ctx)
);
if (hasLink) return;
// Open link editor
ctx.get(linkTooltipAPI.key).addLink(selection.from, selection.to);
};
// Create editor with link tooltip
const editor = await Editor.make()
.config(ctx => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
configureLinkTooltip(ctx); // Required configuration
})
.config(nord)
.use(commonmark)
.use(linkTooltipPlugin)
.create();
// Add button to trigger link insertion
document.getElementById('insert-link-btn')?.addEventListener('click', () => {
editor.action(insertLink);
});
```
--------------------------------
### Create Selection-based Tooltips with tooltipFactory
Source: https://context7.com/milkdown/examples/llms.txt
Uses tooltipFactory to create a custom tooltip plugin that renders a React component when text is selected. Requires the @prosemirror-adapter/react package for view integration.
```tsx
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { Milkdown, MilkdownProvider, useEditor, useInstance } from '@milkdown/react';
import { nord } from '@milkdown/theme-nord';
import { tooltipFactory, TooltipProvider } from '@milkdown/kit/plugin/tooltip';
import { toggleStrongCommand } from '@milkdown/kit/preset/commonmark';
import { usePluginViewFactory, usePluginViewContext } from '@prosemirror-adapter/react';
import { callCommand } from '@milkdown/kit/utils';
import { useCallback, useEffect, useRef, type FC } from 'react';
import type { Ctx } from '@milkdown/kit/ctx';
import '@milkdown/theme-nord/style.css';
// Create tooltip plugin instance
export const tooltip = tooltipFactory('TextFormatting');
// Tooltip React component
const TooltipView: FC = () => {
const ref = useRef(null);
const tooltipProvider = useRef();
const { view, prevState } = usePluginViewContext();
const [loading, get] = useInstance();
const action = useCallback((fn: (ctx: Ctx) => void) => {
if (loading) return;
get().action(fn);
}, [loading, get]);
useEffect(() => {
if (loading || !ref.current) return;
tooltipProvider.current = new TooltipProvider({ content: ref.current });
return () => tooltipProvider.current?.destroy();
}, [loading]);
useEffect(() => {
tooltipProvider.current?.update(view, prevState);
});
return (
);
};
// Editor with tooltip
const Editor: FC = () => {
const pluginViewFactory = usePluginViewFactory();
useEditor((root) => {
return Editor.make()
.config(ctx => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, 'Select text to see tooltip');
ctx.set(tooltip.key, {
view: pluginViewFactory({ component: TooltipView })
});
})
.config(nord)
.use(commonmark)
.use(tooltip)
}, [pluginViewFactory]);
return ;
};
```
--------------------------------
### Solid.js Integration with Milkdown
Source: https://context7.com/milkdown/examples/llms.txt
Integrates Milkdown into a Solid.js application using lifecycle hooks for mounting and cleanup. Remember to import the theme CSS.
```tsx
import { onCleanup, onMount } from "solid-js";
import { defaultValueCtx, Editor, rootCtx } from "@milkdown/kit/core";
import { commonmark } from "@milkdown/kit/preset/commonmark";
import { nord } from "@milkdown/theme-nord";
import "@milkdown/theme-nord/style.css";
const markdown = `# Milkdown + Solid
> Reactive editing with Solid.js.
Edit your **markdown** content here.`;
const MilkdownEditor = () => {
let ref!: HTMLDivElement;
let editor: Editor;
onMount(async () => {
editor = await Editor.make()
.config((ctx) => {
ctx.set(rootCtx, ref);
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
.create();
});
onCleanup(() => {
editor?.destroy();
});
return ;
};
export default MilkdownEditor;
```
--------------------------------
### Implement Draggable Block Handles
Source: https://context7.com/milkdown/examples/llms.txt
Uses the BlockProvider and pluginViewFactory to render a custom React component as a draggable handle for content blocks.
```tsx
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { Milkdown, MilkdownProvider, useEditor, useInstance } from '@milkdown/react';
import { block } from '@milkdown/kit/plugin/block';
import { cursor } from '@milkdown/kit/plugin/cursor';
import { BlockProvider } from '@milkdown/kit/plugin/block';
import { usePluginViewFactory } from '@prosemirror-adapter/react';
import { nord } from '@milkdown/theme-nord';
import { useEffect, useRef, type FC } from 'react';
import '@milkdown/theme-nord/style.css';
// Block handle React component
const BlockView: FC = () => {
const ref = useRef(null);
const blockProvider = useRef();
const [loading, get] = useInstance();
useEffect(() => {
if (loading || !ref.current) return;
const editor = get();
if (!editor) return;
blockProvider.current = new BlockProvider({
ctx: editor.ctx,
content: ref.current,
});
blockProvider.current.update();
return () => blockProvider.current?.destroy();
}, [loading, get]);
return (
);
};
// Editor with block handles
const Editor: FC = () => {
const pluginViewFactory = usePluginViewFactory();
useEditor((root) => {
return Editor.make()
.config(ctx => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, '# Drag me\n\nHover to see handles');
ctx.set(block.key, {
view: pluginViewFactory({ component: BlockView })
});
})
.config(nord)
.use(commonmark)
.use(block)
.use(cursor)
}, [pluginViewFactory]);
return ;
};
```
--------------------------------
### Implement Slash Commands with slashFactory
Source: https://context7.com/milkdown/examples/llms.txt
Uses slashFactory to trigger a custom menu when the user types '/'. The implementation includes manual removal of the trigger character before executing editor commands.
```tsx
import { defaultValueCtx, Editor, editorViewCtx, rootCtx } from '@milkdown/kit/core';
import { commonmark, createCodeBlockCommand } from '@milkdown/kit/preset/commonmark';
import { Milkdown, MilkdownProvider, useEditor, useInstance } from '@milkdown/react';
import { slashFactory, SlashProvider } from '@milkdown/kit/plugin/slash';
import { usePluginViewFactory, usePluginViewContext } from '@prosemirror-adapter/react';
import { callCommand } from '@milkdown/kit/utils';
import { nord } from '@milkdown/theme-nord';
import { useCallback, useEffect, useRef, type FC } from 'react';
import type { Ctx } from '@milkdown/kit/ctx';
import '@milkdown/theme-nord/style.css';
// Create slash plugin instance
export const slash = slashFactory('Commands');
// Slash menu React component
const SlashView: FC = () => {
const ref = useRef(null);
const slashProvider = useRef();
const { view, prevState } = usePluginViewContext();
const [loading, get] = useInstance();
const action = useCallback((fn: (ctx: Ctx) => void) => {
if (loading) return;
get().action(fn);
}, [loading, get]);
useEffect(() => {
if (loading || !ref.current) return;
slashProvider.current = new SlashProvider({ content: ref.current });
return () => slashProvider.current?.destroy();
}, [loading]);
useEffect(() => {
slashProvider.current?.update(view, prevState);
});
const insertCodeBlock = (e: React.MouseEvent) => {
e.preventDefault();
action((ctx) => {
const view = ctx.get(editorViewCtx);
const { dispatch, state } = view;
const { tr, selection } = state;
// Remove the "/" character
dispatch(tr.deleteRange(selection.from - 1, selection.from));
view.focus();
callCommand(createCodeBlockCommand.key)(ctx);
});
};
return (
);
};
// Editor with slash commands
const Editor: FC = () => {
const pluginViewFactory = usePluginViewFactory();
useEditor((root) => {
return Editor.make()
.config(ctx => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, 'Type / to see commands');
ctx.set(slash.key, {
view: pluginViewFactory({ component: SlashView })
});
})
.config(nord)
.use(commonmark)
.use(slash)
}, [pluginViewFactory]);
return ;
};
```
--------------------------------
### Configure Enhanced Code Blocks in TypeScript
Source: https://context7.com/milkdown/examples/llms.txt
Integrates CodeMirror into Milkdown code blocks, enabling language selection and custom rendering for language labels.
```typescript
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { html } from '@milkdown/kit/component';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import { codeBlockComponent, codeBlockConfig } from '@milkdown/kit/component/code-block';
import { languages } from '@codemirror/language-data';
import { basicSetup } from 'codemirror';
import { oneDark } from '@codemirror/theme-one-dark';
import { keymap } from '@codemirror/view';
import { defaultKeymap } from '@codemirror/commands';
import '@milkdown/theme-nord/style.css';
const markdown = `# Code Block Component
\`\`\`typescript
import { Editor } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
const editor = await Editor.make()
.use(commonmark)
.create();
\`\`\`
Code blocks now have language selection and full CodeMirror features.`;
// Checkmark icon for selected language
const checkIcon = html`
`;
await Editor.make()
.config(ctx => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
// Configure code block component
ctx.update(codeBlockConfig.key, defaultConfig => ({
...defaultConfig,
languages, // All CodeMirror languages
extensions: [basicSetup, oneDark, keymap.of(defaultKeymap)],
renderLanguage: (language, isSelected) => {
return html`${isSelected ? checkIcon : null}${language}`;
},
}));
})
.config(nord)
.use(commonmark)
.use(codeBlockComponent)
.create();
```
--------------------------------
### Create Custom Markdown Nodes
Source: https://context7.com/milkdown/examples/llms.txt
Defines a custom iframe node using $node, $remark, and $inputRule to support custom directive syntax in markdown.
```typescript
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import { $inputRule, $node, $remark } from '@milkdown/kit/utils';
import { Node } from '@milkdown/kit/prose/model';
import { InputRule } from '@milkdown/kit/prose/inputrules';
import directive from 'remark-directive';
import '@milkdown/theme-nord/style.css';
const markdown = `# Custom Iframe Syntax
::iframe{src="https://milkdown.dev"}
Use \`::iframe{src="URL"}\` to embed iframes.`;
// Add remark-directive for parsing custom syntax
const remarkDirective = $remark('remarkDirective', () => directive);
// Define custom iframe node
const iframeNode = $node('iframe', () => ({
group: 'block',
atom: true,
isolating: true,
marks: '',
attrs: {
src: { default: null },
},
parseDOM: [{
tag: 'iframe',
getAttrs: (dom) => ({
src: (dom as HTMLElement).getAttribute('src'),
}),
}],
toDOM: (node: Node) => ['iframe', {
...node.attrs,
contenteditable: 'false',
width: '100%',
height: '400px',
}, 0],
parseMarkdown: {
match: (node) => node.type === 'leafDirective' && node.name === 'iframe',
runner: (state, node, type) => {
state.addNode(type, { src: (node.attributes as { src: string }).src });
},
},
toMarkdown: {
match: (node) => node.type.name === 'iframe',
runner: (state, node) => {
state.addNode('leafDirective', undefined, undefined, {
name: 'iframe',
attributes: { src: node.attrs.src },
});
},
}
}));
// Input rule for typing iframe syntax
const iframeInputRule = $inputRule((ctx) =>
new InputRule(/::iframe\{src="(?[^"]+)?"?\}/, (state, match, start, end) => {
const [, src = ''] = match;
const { tr } = state;
tr.replaceWith(start - 1, end, iframeNode.type(ctx).create({ src }));
return tr;
})
);
Editor.make()
.config(ctx => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
.use([...remarkDirective, iframeNode, iframeInputRule])
.create();
```
--------------------------------
### Svelte Integration with Milkdown
Source: https://context7.com/milkdown/examples/llms.txt
Integrates Milkdown into a Svelte application using the `use:` directive for direct DOM manipulation. Ensure the theme CSS is imported.
```svelte
```
--------------------------------
### React Milkdown Integration with useEditor Hook
Source: https://context7.com/milkdown/examples/llms.txt
Integrate Milkdown into React applications using the useEditor hook from @milkdown/react. Wrap your editor component with MilkdownProvider.
```tsx
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import type { FC } from 'react';
import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import '@milkdown/theme-nord/style.css';
const markdown = `# React Milkdown Editor
> Integrate seamlessly with React components.
Type your **markdown** here.`;
const MilkdownEditor: FC = () => {
useEditor((root) => {
return Editor
.make()
.config(ctx => {
ctx.set(rootCtx, root)
ctx.set(defaultValueCtx, markdown)
})
.config(nord)
.use(commonmark)
}, []) // Dependency array for re-initialization
return
}
// Wrap in provider at app level
const App: FC = () => (
)
```
--------------------------------
### Add Image Blocks with Captions in TypeScript
Source: https://context7.com/milkdown/examples/llms.txt
Enables the image block component to support editable captions and automatic upload placeholders for empty images.
```typescript
import { defaultValueCtx, Editor, rootCtx } from '@milkdown/kit/core';
import { commonmark } from '@milkdown/kit/preset/commonmark';
import { nord } from '@milkdown/theme-nord';
import { imageBlockComponent } from '@milkdown/kit/component/image-block';
import '@milkdown/theme-nord/style.css';
const markdown = `# Image Block Component

![]()
Empty image blocks show upload placeholders.`;
await Editor.make()
.config(ctx => {
ctx.set(rootCtx, '#app');
ctx.set(defaultValueCtx, markdown);
})
.config(nord)
.use(commonmark)
.use(imageBlockComponent)
.create();
```
--------------------------------
### Vue Milkdown Integration with useEditor Hook
Source: https://context7.com/milkdown/examples/llms.txt
Integrate Milkdown into Vue 3 applications using the useEditor hook from @milkdown/vue with Vue's composition API. Use MilkdownProvider for component composition.
```vue
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.