vue-modern-monaco-mdc
v0.1.0
Published
Vue 3 composables and components for modern-monaco editor with MDC support
Downloads
113
Maintainers
Readme
vue-modern-monaco-mdc
Vue 3 composables and components for modern-monaco editor, with optional MDC (Markdown Components) support.
Features
- Vue 3 Components — Ready-to-use
<MonacoEditor>and<MonacoDiffEditor>components - Composables — Flexible
useMonaco(),useMonacoDiff(), anduseMonacoOptions()composables - Themes — Built-in dark and light themes (Vitesse)
- Syntax Highlighting — Powered by Shiki via modern-monaco
- MDC Support — Optional Markdown Components support with autocomplete (tree-shakable)
- Reactive — Full Vue reactivity support with
v-model - TypeScript — Full TypeScript support
Installation
npm install vue-modern-monaco-mdc
# or
pnpm add vue-modern-monaco-mdc
# or
yarn add vue-modern-monaco-mdcQuick Start
Using Components
<template>
<MonacoEditor
v-model="code"
language="typescript"
theme="vitesse-dark"
style="height: 400px"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MonacoEditor } from 'vue-modern-monaco-mdc'
const code = ref(`function hello() {
console.log('Hello, World!')
}`)
</script>Using Composables
For more control over the editor lifecycle:
<template>
<div ref="container" style="height: 400px" />
</template>
<script setup lang="ts">
import { ref, shallowRef } from 'vue'
import { useMonaco } from 'vue-modern-monaco-mdc'
const container = shallowRef<HTMLElement | null>(null)
const content = ref('const hello = "world"')
const { editor, isReady } = useMonaco({
container,
content,
language: 'typescript',
theme: 'vitesse-dark',
onChange: (value) => console.log('Content changed:', value),
})
</script>Examples
Diff Editor
Compare two versions of code side-by-side:
<template>
<MonacoDiffEditor
:original="originalCode"
v-model:modified="modifiedCode"
language="typescript"
theme="vitesse-dark"
style="height: 400px"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MonacoDiffEditor } from 'vue-modern-monaco-mdc'
const originalCode = ref(`function add(a: number, b: number): number {
return a + b
}`)
const modifiedCode = ref(`function add(a: number, b: number): number {
// Add two numbers together
const result = a + b
return result
}`)
</script>Accessing the Editor Instance
<template>
<div>
<button @click="formatCode">Format Code</button>
<MonacoEditor ref="editorRef" v-model="code" language="typescript" style="height: 400px" />
</div>
</template>
<script setup lang="ts">
import { ref, shallowRef } from 'vue'
import { MonacoEditor } from 'vue-modern-monaco-mdc'
const code = ref(`function example() {
return "unformatted code"
}`)
const editorRef = shallowRef<InstanceType<typeof MonacoEditor> | null>(null)
async function formatCode() {
const editor = editorRef.value?.editor
await editor?.getAction('editor.action.formatDocument')?.run()
}
</script>MDC (Markdown Components) Support
MDC support is optional and tree-shakable. Import from the /mdc subpath to avoid bundling it when not needed.
<template>
<MonacoEditor
v-model="code"
language="mdc"
theme="vitesse-dark"
:on-setup="setupMDC"
style="height: 400px"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MonacoEditor } from 'vue-modern-monaco-mdc'
import { registerMdcLanguage, setupSuggestion } from 'vue-modern-monaco-mdc/mdc'
import type { Monaco } from 'vue-modern-monaco-mdc'
import type { ComponentMeta, TreeItem } from 'vue-modern-monaco-mdc/mdc'
const code = ref(`# My Document\n\n::my-component{prop="value"}\nContent here\n::`)
const componentsMeta: ComponentMeta[] = [
{
name: 'my-component',
path: '/components/MyComponent.vue',
meta: {
props: [{ name: 'prop', type: 'string', required: false }],
slots: [{ name: 'default', description: 'Default slot content' }]
}
}
]
const mediaTree: TreeItem[] = [
{ name: 'image.png', fsPath: '/images/image.png', type: 'file' }
]
function setupMDC(monaco: Monaco) {
registerMdcLanguage(monaco)
setupSuggestion(monaco, componentsMeta, mediaTree, (key, defaultVal) => defaultVal || key)
}
</script>Markdown Toolbar
The /mdc subpath exports formatting utilities for building toolbar buttons:
<template>
<div class="toolbar">
<button @click="toggleBold(editor)">Bold</button>
<button @click="toggleItalic(editor)">Italic</button>
<button @click="onHeading(editor)">Heading</button>
<button @click="onUnorderedList(editor)">List</button>
<button @click="onLink(editor)">Link</button>
</div>
</template>
<script setup lang="ts">
import type { MonacoEditorInstance } from 'vue-modern-monaco-mdc'
import { toggleBold, toggleItalic, onHeading, onUnorderedList, onLink } from 'vue-modern-monaco-mdc/mdc'
const props = defineProps<{ editor: MonacoEditorInstance }>()
</script>API Reference
Components
<MonacoEditor>
| Prop | Type | Default | Description |
| ------------ | --------------------- | ---------------- | ---------------------------------------- |
| modelValue | string | — | Editor content (v-model) |
| language | string | 'plaintext' | Language mode |
| theme | string | 'vitesse-dark' | Theme name |
| options | MonacoEditorOptions | — | Additional editor options |
| onSetup | (monaco) => void | — | Callback when Monaco instance is ready |
Events: update:modelValue, ready
Slots: loading — custom loading state
Exposed: editor, monaco, isReady
<MonacoDiffEditor>
| Prop | Type | Default | Description |
| ---------- | --------------------- | ---------------- | -------------------------------------- |
| original | string | — | Original content (left side) |
| modified | string | — | Modified content (v-model:modified) |
| language | string | 'plaintext' | Language mode |
| theme | string | 'vitesse-dark' | Theme name |
| options | MonacoEditorOptions | — | Additional editor options |
Events: update:modified, ready
Slots: loading
Composables
useMonaco(options)
const { editor, monaco, isReady, getValue, setValue, focus } = useMonaco({
container: Ref<HTMLElement | null>,
content: Ref<string>,
language?: MaybeRef<string>,
theme?: MaybeRef<string>,
options?: MonacoEditorOptions,
onChange?: (value: string) => void,
onSetup?: (monaco: Monaco) => void,
})useMonacoDiff(options)
const { editor, monaco, isReady, getModifiedValue, setModifiedValue } = useMonacoDiff({
container: Ref<HTMLElement | null>,
original: Ref<string>,
modified: Ref<string>,
language?: MaybeRef<string>,
theme?: MaybeRef<string>,
options?: MonacoEditorOptions,
onChange?: (value: string) => void,
})useMonacoOptions(editor, options?)
Reactive bindings for common editor settings. Changes to the returned refs are automatically applied to the editor.
const { lineNumbers, folding, wordWrap, minimap, scrollBeyondLastLine } = useMonacoOptions(
editor: MonacoEditorInstance | MonacoDiffEditorInstance | null,
options?: {
defaults?: Partial<MonacoOptions> | Ref<Partial<MonacoOptions>>
}
)
// Toggle options directly
lineNumbers.value = true
wordWrap.value = falseThemes
Built-in themes: vitesse-dark (default), vitesse-light
Register a custom theme:
import { getMonaco, registerCustomTheme } from 'vue-modern-monaco-mdc'
const monaco = await getMonaco()
registerCustomTheme(monaco, 'my-theme', {
base: 'vs-dark',
inherit: true,
rules: [],
colors: { 'editor.background': '#1a1a1a' },
})Utilities
import { loadMonaco, getMonaco } from 'vue-modern-monaco-mdc'
// Load Monaco with specific languages
const monaco = await loadMonaco({ theme: 'vitesse-dark', langs: ['typescript', 'javascript'] })
// Get the already-loaded Monaco instance
const monaco = await getMonaco()MDC Functions (vue-modern-monaco-mdc/mdc)
Language Registration
| Function | Description |
| -------------------------- | ---------------------------------------------------- |
| registerMdcLanguage(monaco) | Register MDC syntax highlighting and code folding |
| mapLanguageToMdc(lang) | Map 'markdown' → 'mdc', pass through others |
Autocomplete
| Function | Description |
| --------------------------------------------------- | ----------------------------------------- |
| setupSuggestion(monaco, meta, tree, t) | Register MDC component/media completions |
| getMediasCompletionItems(monaco, range, trigger, tree) | Get completion items for media files |
Formatting Utilities
| Function | Description |
| -------------------------- | ---------------------------------------------- |
| onUndo(editor) | Undo last action |
| onRedo(editor) | Redo last action |
| onHeading(editor) | Toggle heading on current line |
| toggleBold(editor) | Toggle bold on selection |
| toggleItalic(editor) | Toggle italic on selection |
| toggleStrikethrough(editor) | Toggle ~~strikethrough~~ on selection |
| toggleCode(editor) | Toggle inline code on selection |
| onLink(editor) | Insert link (uses clipboard URL if available) |
| onImage(editor) | Insert image (uses clipboard URL if image) |
| onBlockquote(editor) | Toggle blockquote on selected lines |
| onCodeBlock(editor) | Insert code block |
| onUnorderedList(editor) | Toggle bullet list on selected lines |
| onOrderedList(editor) | Toggle numbered list on selected lines |
| onTable(editor) | Insert table template |
| onPrettify(editor) | Clean up markdown formatting |
TypeScript
import type {
Monaco,
MonacoEditor as MonacoEditorInstance,
MonacoDiffEditor as MonacoDiffEditorInstance,
MonacoEditorOptions,
UseMonacoOptions,
UseMonacoReturn,
UseMonacoOptionsOptions,
} from 'vue-modern-monaco-mdc'
import type { ComponentMeta, TreeItem } from 'vue-modern-monaco-mdc/mdc'Browser Support
Modern browsers with ES module support. Monaco Editor uses Web Workers — ensure your build tool handles them correctly.
License
MIT
Related Projects
- modern-monaco — The underlying Monaco Editor wrapper
- Monaco Editor — Microsoft's code editor
