A component for using CodeMirror6 with Vue. This component works in both Vue2 and Vue3.
yarn add vue-codemirror6 codemirrorFor Vue 2.7 or below, @vue/composition-api is required separately.
yarn add vue-codemirror6 @vue/composition-apiThis component can handle bidirectional binding by v-model like a general Vue component.
| Props | Type | Information | 
|---|---|---|
| model-value | string | Text | Text value. (Not value) | 
| basic | boolean | Use basicSetup. | 
| minimal | boolean | Use miniSetup. If a basicprop is also specified, that setting will take precedence. | 
| dark | boolean | Toggle Darkmode. | 
| placeholder | string | Add placeholder text (or HTML DOM) when blank | 
| wrap | boolean | Line text wrapping. see lineWrapping. | 
| tab | boolean | Enables tab indentation. | 
| allow-multiple-selections | boolean | Allow Multiple Selection. See allowMultipleSelections | 
| tab-size | number | Configures the tab size to use in this state. | 
| line-separator | string | Set line break (separetor) char. (Default is \n.) | 
| theme | { [selector: string]: StyleSpec } | Specify the theme. For example, if you use @codemirror/theme-one-dark, import oneDarkand put it in this prop. | 
| readonly | boolean | Makes the cursor visible or you can drag the text but not edit the value. | 
| disabled | boolean | This is the reversed value of the CodeMirror editable. Similar to readonly, but setting this value to true disables dragging. | 
| lang | LanguageSupport | The language you want to have syntax highlighting. see https://codemirror.net/6/#languages | 
| phrases | Record<string, string> | Specify here if you want to make the displayed character string multilingual. see https://codemirror.net/6/examples/translate/ | 
| extensions | Extension[] | Includes enhancements to extend CodeMirror. | 
| linter | LintSource | Set Linter. Enter a linter (eg esLint([arbitrary rule])function for@codemirror/lang-javascript,jsonParseLinter()function for@codemirror/json). See the sources for various language libraries for more information. | 
| linterConfig | Object | see https://codemirror.net/docs/ref/#lint.linter^config | 
| forceLinting | boolean | see https://codemirror.net/docs/ref/#lint.forceLinting | 
| gutter | boolean | Display 🔴 on the line where there was an error when linterwas specified. It will not work iflinteris not specified. | 
| gutterConfig | Object | see https://codemirror.net/docs/ref/#lint.lintGutter^config | 
| tag | string | HTML tags used in the component. (Default is divtag.) | 
| scrollIntoView | boolean | Allows an external update to scroll the form. (Default is true) | 
| keymap | KeyBinding[] | Key bindings associate key names with command-style functions. See https://codemirror.net/docs/ref/#view.KeyBinding | 
⚠ Notice: lang and linter can also be set together in extensions. These are separated for compatibility with previous versions of CodeMirror settings and for typing props.
- @codemirror/lang-angular
- @codemirror/lang-cpp
- @codemirror/lang-css
- @codemirror/lang-html
- @codemirror/lang-java
- @codemirror/lang-javascript
- @codemirror/lang-json
- @codemirror/lang-lezer
- @codemirror/lang-markdown
- @codemirror/lang-php
- @codemirror/lang-python
- @codemirror/lang-rust
- @codemirror/lang-sql
- @codemirror/lang-vue
- @codemirror/lang-west
- @codemirror/lang-xml
- @phoenix-plugin-registry/petetnt.brackets-codemirror-fortran
- @phoenix-plugin-registry/petetnt.brackets-codemirror-go
- @acarl005/lang-sql
- @ark-us/codemirror-lang-taylor
- @formulavize/lang-fiz
- @gravitywiz/codemirror-lang-gfcalc
- @nextjournal/lang-clojure
- @plutojl/lang-julia
- @polybase/codemirror-lang-javascript-- @replit/codemirror-lang-nix
- @replit/codemirror-lang-csharp
- @replit/codemirror-lang-solidity
- @replit/codemirror-lang-svelte
- @zhijiu/lang-sql
- codemirror-lang-bool
- codemirror-lang-brainfuck
- codemirror-lang-cherry
- codemirror-lang-chordpro
- codemirror-lang-circom
- codemirror-lang-edn
- codemirror-lang-ejs
- codemirror-lang-fsl
- codemirror-lang-gml
- codemirror-lang-golfscript
- codemirror-lang-homescript
- codemirror-lang-html-n8n
- codemirror-lang-inform7
- codemirror-lang-j
- codemirror-lang-janet
- codemirror-lang-k
- codemirror-lang-karol
- codemirror-lang-mermaid
- codemirror-lang-n8n-expression
- codemirror-lang-prolog
- codemirror-lang-qpen
- codemirror-lang-qtam
- codemirror-lang-r
- codemirror-lang-rome-ast
- codemirror-lang-rome
- codemirror-lang-rush
- codemirror-lang-scopescript
- codemirror-lang-statement
- gcode-lang-codemirror
- gmail-lang
- lang-bqn
- lang-clojure
- lang-d
- lang-feel
- lang-firestore
Mark up as follows to make it work at a minimum.
<template>
  <code-mirror v-model="value" />
</template>
<script>
import { ref, defineComponent } from 'vue';
import CodeMirror from 'vue-codemirror6';
export default defineComponent({
  components: {
    CodeMirror,
  },
  setup() {
    const value = ref('Cozy lummox gives smart squid who asks for job pen.');
    return { value };
  },
});
</script>The contents of the slot will overwrite the existing v-model. For this reason, it is recommended to use it when simply displaying with a readonly prop without using v-model.
Also, insert a <pre> tag to prevent the text in the slot from being automatically formatted.
<template>
  <code-mirror :lang="lang" :linter="linter">
    <pre>
{
  "key": "value"
}</pre
    >
  </code-mirror>
</template>
<script>
import { ref, defineComponent } from 'vue';
import { json, jsonParseLinter } from '@codemirror/lang-json';
import CodeMirror from 'vue-codemirror6';
export default defineComponent({
  components: {
    CodeMirror,
  },
  setup() {
    const lang = json();
    const linter = jsonParseLinter();
    return { lang, linter };
  },
});
</script>This component is now SSR-compatible. CodeMirror will only be initialized on the client side, and the component will safely render without errors during server-side rendering.
If you're using Nuxt 3, you can use the component directly:
<template>
  <code-mirror v-model="value" :lang="lang" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import CodeMirror from 'vue-codemirror6';
import { javascript } from '@codemirror/lang-javascript';
const value = ref('console.log("Hello, World!");');
const lang = javascript();
</script>For Nuxt 2 or if you encounter any issues, you can wrap the component with <ClientOnly>:
<template>
  <client-only>
    <code-mirror v-model="value" :lang="lang" />
  </client-only>
</template>When using as a Markdown editor on vite-vue3-ts-starter.
<script lang="ts" setup>
import { ref, defineComponent, type Ref } from 'vue';
// Load component
import CodeMirror from 'vue-codemirror6';
// CodeMirror extensions
import { markdown as md } from '@codemirror/lang-markdown';
import type { LanguageSupport } from '@codemirror/language';
import type { Extension } from '@codemirror/state';
import type { ViewUpdate } from '@codemirror/view';
/** text */
const value: Ref<string> = ref('');
/** Dark mode **/
const dark: Ref<boolean> = ref(
  window.matchMedia('(prefers-color-scheme: dark)').matches
);
/**
 * CodeMirror Language
 *
 * @see {@link https://codemirror.net/6/docs/ref/#language | @codemirror/language}
 */
const lang: LanguageSupport = md();
/**
 * Internationalization Config.
 * In this example, the display language to Japanese.
 * Must be reactive when used in combination with vue-i18n.
 *
 * @see {@link https://codemirror.net/6/examples/translate/ | Example: Internationalization}
 */
const phrases: Record<string, string> = {
  // @codemirror/view
  'Control character': '制御文字',
  // @codemirror/commands
  'Selection deleted': '選択を削除',
  // @codemirror/language
  'Folded lines': '折り畳まれた行',
  'Unfolded lines': '折り畳める行',
  to: '行き先',
  'folded code': '折り畳まれたコード',
  unfold: '折り畳みを解除',
  'Fold line': '行を折り畳む',
  'Unfold line': '行の折り畳む解除',
  // @codemirror/search
  'Go to line': '行き先の行',
  go: 'OK',
  Find: '検索',
  Replace: '置き換え',
  next: '▼',
  previous: '▲',
  all: 'すべて',
  'match case': '一致条件',
  'by word': '全文検索',
  regexp: '正規表現',
  replace: '置き換え',
  'replace all': 'すべてを置き換え',
  close: '閉じる',
  'current match': '現在の一致',
  'replaced $ matches': '$ 件の一致を置き換え',
  'replaced match on line $': '$ 行の一致を置き換え',
  'on line': 'した行',
  // @codemirror/autocomplete
  Completions: '自動補完',
  // @codemirror/lint
  Diagnostics: 'エラー',
  'No diagnostics': 'エラーなし',
};
</script>
<template>
  <code-mirror
    v-model="value"
    basic
    :dark="dark"
    :lang="lang"
    :phrases="phrases"
  />
</template>| Event | Description | 
|---|---|
| ready | When CodeMirror loaded. | 
| focus | When focus changed. | 
| update | When CodeMirror state changed. Returns ViewUpdate object. | 
| change | Value changed. Returns EditorState | 
<script setup lang="ts">
import { ref, onMounted, type Ref, type PropType } from 'vue';
import CodeMirror from 'vue-codemirror6';
const cm: Ref<InstanceType<typeof CodeMirror> | undefined> = ref();
onMounted(() => {
  console.log(cm.value?.json);
});
</script>
<template>
  <code-mirror ref="cm" />
</template>| Function / Parameter | Description | 
|---|---|
| view | Get and set EditorView. | 
| selection | Get and set the EditorSelection instance. | 
| cursor | Get and set the cursor location. | 
| json | Get and set state to a JSON-serializable object. | 
| focus | Get and set focus. | 
| lint() | Force run linter (Only if linterprop is specified) | 
| forceReconfigure() | Re register all extensions. | 
The instructions below are compatible methods for those familiar with codemirror5. Since the above method is usually sufficient, its active use is not recommended.
| Function | Description | 
|---|---|
| getRange(from?: number, to?: number) | Get the text between the given points in the editor. | 
| getLine(number: number) | Get the content of line. | 
| lineCount() | Get the number of lines in the editor. | 
| getCursor() | Retrieve one end of the primary selection. | 
| listSelections() | Retrieves a list of all current selections. | 
| getSelection() | Get the currently selected code. | 
| getSelections() | The length of the given array should be the same as the number of active selections. | 
| somethingSelected() | Return true if any text is selected. | 
| replaceRange(replacement: string | Text, from: number, to: number) | Replace the part of the document between from and to with the given string. | 
| replaceSelection(replacement: string | Text) | Replace the selection(s) with the given string. | 
| setCursor(position: number) | Set the cursor position. | 
| setSelection(anchor: number, head?: number) | Set a single selection range. | 
| setSelections(ranges: readonly SelectionRange[], primary?: number) | Sets a new set of selections. | 
| extendSelectionsBy(f: Function) | Applies the given function to all existing selections, and calls extendSelections on the result. | 
Since CodeMirror has a relatively large capacity, when using vite, it is recommended to set it to output as a separate file using the manualChunks option at build time as shown below.
const config: UserConfig = {
  // ...
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          // ...
          codemirror: ['vue-codemirror6'],
          'codemirror-lang': [
            // Add the following as needed.
            '@codemirror/lang-html',
            '@codemirror/lang-javascript',
            '@codemirror/lang-markdown',
          ],
          // ...
        },
      },
    },
  },
  // ...
};This project uses Vitest for unit testing.
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with UI
pnpm test:ui
# Run tests with coverage
pnpm test:coverageThe test suite includes:
- Component Tests: Testing basic rendering, props, events, and v-model binding
- SSR Tests: Ensuring proper server-side rendering compatibility for Nuxt.js and other SSR frameworks
- Method Tests: Verifying all exposed methods work correctly
- Edge Cases: Testing error handling and unusual scenarios
©2022-2025 by Logue. Licensed under the MIT License.
