Use it online: Go.

🔖 MdPreview Props

This is the props of MdPreview, which is also part of MdEditor:

📃 modelValue

  • type: string

  • default: ''

    Markdown content.

    vue Copy
    <MdEditor v-model="xxx" />

🛍 theme

  • type: 'light' | 'dark'

  • default: 'light'

    Editor's theme.

    vue Copy
    <MdEditor theme="dark" />

🎀 class

  • type: string

  • default: ''

    ...


🔤 language

  • type: string

  • default: 'zh-CN'

    Build-in language('zh-CN', 'en-US').

    You can install the existing language also: md-editor-extension. Refer to extension library for the usage and the way to contribute~


🎲 editorId

  • type: string

  • default: 'md-editor-v-\d'

    Deprecated. Starting from version 5.x, Replace with id.

    Unique identifier of the editor, use the default prefix and useId for concatenation. When using server-side rendering, make sure to set this attribute to a constant value.,Starting from version 5.0, there is no such limitation.


🎲 id

  • type: string

  • default: 'md-editor-v-\d'

    Unique identifier of the editor, use the default prefix and useId for concatenation.


🔢 showCodeRowNumber

  • type: boolean

  • default: true

    Show row number for code block or not.


🔦 previewTheme

  • type: 'default' | 'github' | 'vuepress' | 'mk-cute' | 'smart-blue' | 'cyanosis'

  • default: 'default'

    Preview themes.

    Custom:

    1. Write css
    css Copy
    .xxx-theme {
      color: red;
    }
    1. Set previewTheme
    vue Copy
    <MdEditor previewTheme="xxx" />

    For more, refer to markdown-theme.


🎅🏻 style

  • type: string | CSSProperties

  • default: ''

    Editor's inline style.


☝️ noMermaid

  • type: boolean

  • default: false

    Do not want to use mermaid, set it to true.

    vue Copy
    <MdEditor noMermaid />

❌ noKatex

  • type: boolean

  • default: false

    Do not want to use katex, set it to true.

    vue Copy
    <MdEditor noKatex />

🦉 codeTheme

  • type: 'atom'|'a11y'|'github'|'gradient'|'kimbie'|'paraiso'|'qtcreator'|'stackoverflow'

  • default: 'atom'

    Highlight code css name. Get Them from highlight.js.

    Custom:

    1. Config editorExtensions
    js Copy
    import { config } from 'md-editor-v3';
    
    config({
      editorExtensions: {
        highlight: {
          css: {
            atom: {
              light:
                'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/atom-one-light.min.css',
              dark: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/atom-one-dark.min.css',
            },
            xxx: {
              light:
                'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/xxx-light.css',
              dark: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/xxx-dark.css',
            },
          },
        },
      },
    });
    1. Set codeTheme
    vue Copy
    <MdEditor codeTheme="xxx" />

🎱 mdHeadingId

  • type: (text: string, level: number, index: number) => string

  • default: (text) => text

    Heading ID generator.

    vue Copy
    <template>
      <MdEditor :mdHeadingId="mdHeadingId" />
    </template>
    
    <script setup>
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const mdHeadingId = (_text, _level, index) => `heading-${index}`;
    </script>

🐣 sanitize

  • type: (html: string) => string

  • default: (html) => html

    This attribute is used to alter the compiled HTML content.

    This is a reserved attribute.

    Basic solution for dangerous code has been built-in since version 3.x. eg: <script>alert(123)</script>. Prior to version 4.11.3, it was recommended to utilize this attribute for cleaning more complex content to prevent XSS attacks.

    A more comprehensive solution has been implemented since version 4.11.3. Refer to

    sanitize-html example:

    vue Copy
    <template>
      <MdEditor :sanitize="sanitize" />
    </template>
    
    <script setup>
    import sanitizeHtml from 'sanitize-html';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const sanitize = (html) => sanitizeHtml(html);
    </script>

💅 formatCopiedText

  • type: (text: string) => string

  • default: (text) => text

    Format copied code

    vue Copy
    <template>
      <MdEditor :formatCopiedText="formatCopiedText" />
    </template>
    
    <script setup>
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const formatCopiedText = (text) => {
      return `${text}  - from md-editor-v3`;
    };
    </script>

🛁 codeStyleReverse

  • type: boolean

  • default: true

    Code style will be reversed to dark while code block of the theme has a dark background.


🧼 codeStyleReverseList

  • type: Array

  • default: ['default', 'mk-cute']

    Themes to be reversed.


🕊 noHighlight

  • type: boolean

  • default: false

    Highlight code or not.


🕊 noImgZoomIn

  • type: boolean

  • default: false

    Enable the function of enlarging images.

    vue Copy
    <MdEditor noImgZoomIn />

    After version 4.15.4, it is also possible to disable zooming by setting the class .not-zoom.

    markdown Copy
    <img class="not-zoom">

😬 customIcon

  • type: CustomIcon

  • default: {}

    Customized icons

    Type Warning

    The icon corresponding to copy and collapse-tips can only be a string, while others can be components or strings

    vue Copy
    <template>
      <MdEditor :customIcon="customIcon" />
    </template>
    
    <script 😬setup lang="ts">
    import type { CustomIcon } from 'md-editor-v3';
    import { MdEditor, StrIcon } from 'md-editor-v3';
    // Assuming you have installed an icon library or customized icon components
    import { IconFont } from 'tdesign-icons-vue-next';
    import 'md-editor-v3/lib/style.css';
    
    const customIcon: CustomIcon = {
      bold: {
        component: 'A',
      },
      // Demonstrating the use of default icons
      copy: StrIcon('copy', {}),
      // copy: '<i class="fa fa-car"></i>',
      // 'collapse-tips': '<i class="fa fa-car"></i>',
      preview: {
        component: '<i class="fa fa-car"></i>',
      },
      github: {
        component: IconFont,
        props: {
          name: 'sneer',
        },
      },
    };
    </script>

    Type CustomIcon

    ts Copy
    type IconName =
      | 'bold'
      | 'underline'
      | 'italic'
      | 'strike-through'
      | 'title'
      | 'sub'
      | 'sup'
      | 'quote'
      | 'unordered-list'
      | 'ordered-list'
      | 'task'
      | 'code-row'
      | 'code'
      | 'link'
      | 'image'
      | 'table'
      | 'revoke'
      | 'next'
      | 'save'
      | 'prettier'
      | 'minimize'
      | 'maximize'
      | 'fullscreen-exit'
      | 'fullscreen'
      | 'preview-only'
      | 'preview'
      | 'preview-html'
      | 'catalog'
      | 'github'
      | 'mermaid'
      | 'formula'
      | 'close'
      | 'delete'
      | 'upload';
    
    type CustomIcon = {
      [key in IconName]?: {
        component: VNode;
        props: {
          [key: string | number | symbol]: any;
        };
      };
    } & {
      copy?: string;
      'collapse-tips': string;
    };

💅 sanitizeMermaid

  • type: (h: string) => Promise<string>

  • default: (h: string) => Promise.resolve(h)

    Convert the generated mermaid code


🕹 codeFoldable

  • type: boolean

  • default: true

    Whether to enable code folding feature


⏲ autoFoldThreshold

  • type: number

  • default: 30

    Threshold for triggering automatic code folding by line count


🔩 MdEditor Props

Except for the same as MdPreview:

💻 pageFullscreen

  • type: boolean

  • default: false

    Screenfull in web page.


📱 preview

  • type: boolean

  • default: true

    Preview content in editor.


📀 htmlPreview

  • type: boolean

  • default: false

    Preview html in editor. Set preview to false when htmlPreview is true.

    jsx Copy
    <MdEditor htmlPreview preview={false} />

🧱 toolbars

  • type: Array

  • default: [all]

    Show contents of toolbar, all keys.

    You can sort the toolbar as you like, split tools by '-', the left and right toolbars are divided by '='

    After v1.10.0, you can customize the toolbar. To display them, put index of defToolbars into toolbars(this is not standard)

    [all]

    js Copy
    [
      'bold',
      'underline',
      'italic',
      '-',
      'title',
      'strikeThrough',
      'sub',
      'sup',
      'quote',
      'unorderedList',
      'orderedList',
      'task',
      '-',
      'codeRow',
      'code',
      'link',
      'image',
      'table',
      'mermaid',
      'katex',
      '-',
      'revoke',
      'next',
      'save',
      '=',
      'pageFullscreen',
      'fullscreen',
      'preview',
      'previewOnly',
      'htmlPreview',
      'catalog',
      'github',
    ];

🧱 toolbarsExclude

  • type: Array

  • default: []

    Don't show contents of toolbar.


🪒 noPrettier

  • type: boolean

  • default: false

    Use prettier to beautify content or not.


🤏 tabWidth

  • type: number

  • default: 2

    One tab eq some space.


📅 tableShape

  • type: [number, number] \| [number, number, number, number]

  • default: [6, 4]

    Preset the size of the table, [columns, rows, Maximum number of columns, Maximum number of rows]

    vue Copy
    <template>
      <MdEditor :tableShape="tableShape" />
    </tempale>
    
    <script setup>
    const tableShape = [8, 4];
    </script>
    Preview

🪧 placeholder

  • type: string

  • default: ''

    em-_-!


🦶 footers

  • type: Array<'markdownTotal' \| '=' \| 'scrollSwitch' \| number>

  • default: ['markdownTotal', '=', 'scrollSwitch']

    Show contents of footer, they are divided by '='. Set it to [] to hidden footer.


⛵️ scrollAuto

  • type: boolean

  • default: true

    Scroll default setting.


🥹 noUploadImg

  • type: boolean

  • default: false

    Not show the entrance to upload pictures

    vue Copy
    <MdEditor noUploadImg />

🔬 autoFocus

  • type: boolean

  • default: false

    Same as autofocus in native textarea.


🔩 disabled

  • type: boolean

  • default: false

    Same as disabled in native textarea.


🔒 readOnly

  • type: boolean

  • default: false

    Same as readonly in native textarea.


📏 maxLength

  • type: number

  • default: ``

    Same as maxlength in native textarea.


📥 autoDetectCode

  • type: boolean

  • default: false

    Auto detect the type of pasted code, only support that copied from vscode.


📝 completions

  • type: Array<CompletionSource>

  • default: []

    Additional completion sources.

    vue Copy
    <template>
      <MdEditor v-model="text" :completions="completions" />
    </template>
    
    <script setup lang="ts">
    import { ref } from 'vue';
    import { CompletionSource } from '@codemirror/autocomplete';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const text = ref('');
    
    const completions = ref<Array<CompletionSource>>([
      (context) => {
        const word = context.matchBefore(/@\w*/);
    
        if (word === null || (word.from == word.to && context.explicit)) {
          return null;
        }
    
        return {
          from: word.from,
          options: [
            {
              label: '@imzbf',
              type: 'text',
            },
          ],
        };
      },
    ]);
    </script>

📥 showToolbarName

  • type: boolean

  • default: false

    Show toolbar name or not


📥 inputBoxWidth

  • type: string

  • default: 50%

    Default width of input box


📥 transformImgUrl

  • type: (imgUrl: string) => string | Promise<string>

  • default: t => t

    Transform image links


🎍 slots

💪 defToolbars

Custom toolbar in DropdownToolbar, NormalToolbar or ModalToolbar.

  • Setup Template

    vue Copy
    <template>
      <MdEditor :toolbars="toolbars">
        <template #defToolbars>
          <NormalToolbar title="mark" @onClick="handler">
            <template #trigger>
              <svg class="md-editor-icon" aria-hidden="true">
                <use xlink:href="#icon-mark"></use>
              </svg>
            </template>
          </NormalToolbar>
        </template>
      </MdEditor>
    </template>
    
    <script setup>
    import { MdEditor, NormalToolbar } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const toolbars = ['bold', '-', 0, '=', 'github'];
    
    const handler = () => {
      console.log('NormalToolbar clicked!');
    };
    </script>
  • Jsx Template

    jsx Copy
    import { defineComponent } from 'vue';
    import { MdEditor, NormalToolbar } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const toolbars = ['bold', '-', 0, '=', 'github'];
    
    export default defineComponent({
      setup() {
        return () => (
          <MdEditor
            toolbars={toolbars}
            defToolbars={
              <>
                <NormalToolbar
                  trigger={
                    <svg class="md-editor-icon" aria-hidden="true">
                      <use xlinkHref="#icon-strike-through" />
                    </svg>
                  }
                />
              </>
            }
          />
        );
      },
    });
NormalToolbar
DropdownToolbar

For more info, Get Internal Components heading. Get source code of mark, emoji and modal preview at docs branch.


🦿 defFooters

  • Setup Template

    vue Copy
    <template>
      <MdEditor :footers="footers">
        <template #defFooters>
          <span>¥_¥</span>
          <span>^_^</span>
        </template>
      </MdEditor>
    </template>
    
    <script setup>
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const footers = ['markdownTotal', 0, '=', 1, 'scrollSwitch'];
    </script>
  • Jsx Template

    jsx Copy
    import { defineComponent } from 'vue';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const footers = ['markdownTotal', 0, '=', 1, 'scrollSwitch'];
    
    export default defineComponent({
      setup() {
        return () => (
          <MdEditor
            footers={footers}
            defFooters={
              <>
                <span>¥_¥</span>
                <span>^_^</span>
              </>
            }
          />
        );
      },
    });

🧵 MdPreview Events

🚁 onHtmlChanged

  • type: (h: string) => void

    Compile markdown successful event, you can use it to get the html code.


🗒 onGetCatalog

  • type: (list: HeadList[]) => void

    Get catalogue of article.


🪢 MdEditor Events

Except for the same as MdPreview:

📞 onChange

  • type: (v: string) => void

    Content changed event(bind to oninput of textarea).


💾 onSave

  • type: (v: string, h: Promise<string>) => void

    Saving content event, ctrl+s and clicking button will trigger it.

    vue Copy
    <template>
      <MdEditor @onSave="onSave" />
    </template>
    
    <script setup>
    import MdEditor from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const onSave = (v, h) => {
      console.log(v);
    
      h.then((html) => {
        console.log(html);
      });
    };
    </script>

📸 onUploadImg

  • type: files: Array<File>, callback: (urls: string[] | { url: string; alt: string; title: string }[]) => void

    Uploading picture event, when picture is uploading the modal will not close, please provide right urls to the callback function.

    vue Copy
    <template>
      <MdEditor v-model="text" @onUploadImg="onUploadImg" />
    </template>
    
    <script setup>
    import { ref } from 'vue';
    import axios from 'axios';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const text = ref('# Hello Editor');
    
    const onUploadImg = async (files, callback) => {
      const res = await Promise.all(
        files.map((file) => {
          return new Promise((rev, rej) => {
            const form = new FormData();
            form.append('file', file);
    
            axios
              .post('/api/img/upload', form, {
                headers: {
                  'Content-Type': 'multipart/form-data',
                },
              })
              .then((res) => rev(res))
              .catch((error) => rej(error));
          });
        })
      );
    
      // Approach 1
      callback(res.map((item) => item.data.url));
    
      // Approach 2
      // callback(
      //   res.map((item: any) => ({
      //     url: item.data.url,
      //     alt: 'alt',
      //     title: 'title'
      //   }))
      // );
    };
    </script>

💀 onError

  • type: (err: { name: 'Cropper' \| 'fullscreen' \| 'prettier' \| 'overlength'; message: string }) => void

    Run-Time error event, only be called when Cropper, fullscreen, prettier is not loaded. And content exceeds the length limit error.

    vue Copy
    <template>
      <MdEditor @onError="onError" />
    </template>
    
    <script setup>
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const onError = (err) => {
      alert(err.message);
    };
    </script>

🐾 onBlur

  • type: (event: FocusEvent) => void

    Textarea has lost focus.

    vue Copy
    <template>
      <MdEditor @onBlur="onBlur" />
    </template>
    
    <script setup>
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const onBlur = (e) => {
      console.log('onBlur', e);
    };
    </script>

🔖 onFocus

  • type: (event: FocusEvent) => void

    Textarea has received focus.


🔖 onInput

  • type: (event: Event) => void

    Element gets input.


🔖 onDrop

  • type: (event: DragEvent) => void

    The event occurs when a selection is being dragged.

    vue Copy
    <template>
      <MdEditor v-model="text" @onDrop="onDrop" />
    </template>
    
    <script setup lang="ts">
    import { ref } from 'vue';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const text = ref('');
    
    const onDrop = (e: DragEvent) => {
      e.stopPropagation();
      console.log('ee', e.dataTransfer?.files[0]);
    };
    </script>

🔖 onInputBoxWidthChange

  • type: (width: string) => void

    Event occurs when width of input box has been changed


🤱🏼 Expose

After 2.5.0, Editor exposes several methods on the instance, used to get or change the internal status of the editor.

vue Copy
<template>
  <MdEditor ref="editorRef" />
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { MdEditor } from 'md-editor-v3';
import type { ExposeParam } from 'md-editor-v3';

//
// import type { ExposePreviewParam } from 'md-editor-v3';

import 'md-editor-v3/lib/style.css';

const editorRef = ref<ExposeParam>();

onMounted(() => {
  editorRef.value?.on('catalog', console.log);
});
</script>
Name MdEditor MdPreview
on ×
togglePageFullscreen ×
toggleFullscreen ×
togglePreview ×
togglePreviewOnly ×
toggleHtmlPreview ×
toggleCatalog ×
triggerSave ×
insert ×
focus ×
rerender
getSelectedText ×
resetHistory ×

👂🏼 on

Get the internal state of the editor, including pageFullscreen, fullscreen, preview, htmlPreview, catalog, etc.

  • pageFullscreen

    js Copy
    editorRef.value?.on('pageFullscreen', (status) => console.log(status));
  • fullscreen

    js Copy
    editorRef.value?.on('fullscreen', (status) => console.log(status));
  • preview

    js Copy
    editorRef.value?.on('preview', (status) => console.log(status));
  • previewOnly

    js Copy
    editorRef.value?.on('previewOnly', (status) => console.log(status));
  • htmlPreview

    js Copy
    editorRef.value?.on('htmlPreview', (status) => console.log(status));
  • catalog

    js Copy
    editorRef.value?.on('catalog', (status) => console.log(status));

💻 togglePageFullscreen

Toggle status of fullscreen within the page.

js Copy
editorRef.value?.togglePageFullscreen(true);

Switched to the opposite status, without input parameter.


🖥 toggleFullscreen

Toggle status of fullscreen widthin browser.

js Copy
editorRef.value?.toggleFullscreen(true);

Switched to the opposite status, without input parameter.


📖 togglePreview

Toggle status of preview.

js Copy
editorRef.value?.togglePreview(true);

Switched to the opposite status, without input parameter.


📖 togglePreviewOnly

Toggle into Preview Only Mode.

js Copy
editorRef.value?.togglePreviewOnly(true);

Switched to the opposite status, without input parameter.


📼 toggleHtmlPreview

Toggle status of htmlPreview.

js Copy
editorRef.value?.toggleHtmlPreview(true);

Switched to the opposite status, without input parameter.


🧬 toggleCatalog

Toggle status of catalog.

js Copy
editorRef.value?.toggleCatalog(true);

Switched to the opposite status, without input parameter.


💾 triggerSave

js Copy
editorRef.value?.triggerSave();

💉 insert

Manually insert content into textarea.

js Copy
/**
 * @params selectedText
 */
editorRef.value?.insert((selectedText) => {
  /**
   * @return targetValue    Content to be inserted
   * @return select         Automatically select content, default: true
   * @return deviationStart Start position of the selected content, default: 0
   * @return deviationEnd   End position of the selected content, default: 0
   */
  return {
    targetValue: `${selectedText}`,
    select: true,
    deviationStart: 0,
    deviationEnd: 0,
  };
});

🎯 focus

Focus on the textarea.

ts Copy
import type { FocusOption } from 'md-editor-v3';

const option: FocusOption | undefined = 'start';

// Cursor position when focusing on textarea, default: position when it last lost focus
editorRef.value?.focus(option);
ts Copy
type FocusOption =
  | 'start'
  | 'end'
  | {
      // Start position, default cursor position
      rangeAnchor?: number;
      // End position, default cursor position
      rangeHead?: number;
      // Cursor position
      cursorPos: number;
    };

✒️ rerender

Re render the content.

js Copy
editorRef.value?.rerender();

🔍 getSelectedText

Get the currently selected text.

js Copy
console.log(editorRef.value?.getSelectedText());

🗑 resetHistory

Clear current history.


🎛 domEventHandlers

Supports listening to all DOM events.

js Copy
editorRef.value?.domEventHandlers({
  compositionstart: () => {
    console.log('compositionstart');
  },
});

🎛 execCommand

Insert content into the editor via trigger.

js Copy
editorRef.value?.execCommand('bold');

🔖 getEditorView

Get codemirror instance.


💴 Config Editor

Use config(option: ConfigOption) to reconfigure markdown-it and so on.

We recommend configuring it at the project entry point, such as in main.js for projects created with Vite. Avoid calling config within components!

🦪 codeMirrorExtensions

Customize new extensions based on theme and default extensions f codeMirror.

ts Copy
type CodeMirrorExtensions = (
  theme: Themes,
  extensions: Array<Extension>,
  keyBindings: Array<KeyBinding>,
  options: {
    editorId: string;
  }
) => Array<Extension>;

Example: Editor does not render the line number of textarea by default, this extension needs to be manually added

js Copy
import { config } from 'md-editor-v3';
import { lineNumbers } from '@codemirror/view';

config({
  codeMirrorExtensions(_theme, extensions) {
    return [...extensions, lineNumbers()];
  },
});

🍤 markdownItConfig

Customize extensions, attributes of markdown-it, etc.

ts Copy
type MarkdownItConfig = (
  md: markdownit,
  options: {
    editorId: string;
  }
) => void;

Example: Use markdown-it-anchor to render a hyperlink symbol to the right of the title

js Copy
import { config } from 'md-editor-v3';
import ancher from 'markdown-it-anchor';

config({
  markdownItConfig(mdit) {
    mdit.use(ancher, {
      permalink: true,
    });
  },
});

🍤 markdownItPlugins

Select and add built-in plugins to markdown-it.

ts Copy
type MarkdownItPlugins = (
  plugins: Array<MarkdownItConfigPlugin>,
  options: {
    editorId: string;
  }
) => Array<MarkdownItConfigPlugin>;

Example: Modify the class name of the image.

js Copy
import { config } from 'md-editor-v3';

config({
  markdownItPlugins(plugins) {
    return plugins.map((p) => {
      if (p.type === 'image') {
        return {
          ...p,
          options: {
            ...p.options,
            classes: 'my-class',
          },
        };
      }

      return p;
    });
  },
});

🍙 editorConfig

Add more languages, reset mermaid template or delay rendering time

🍚 languageUserDefined

js Copy
import { config } from 'md-editor-v3';

config({
  editorConfig: {
    languageUserDefined: {
      'en-US': {
        toolbarTips: {
          bold: 'bold',
          underline: 'underline',
          italic: 'italic',
          strikeThrough: 'strikeThrough',
          title: 'title',
          sub: 'subscript',
          sup: 'superscript',
          quote: 'quote',
          unorderedList: 'unordered list',
          orderedList: 'ordered list',
          task: 'task list',
          codeRow: 'inline code',
          code: 'block-level code',
          link: 'link',
          image: 'image',
          table: 'table',
          mermaid: 'mermaid',
          katex: 'formula',
          revoke: 'revoke',
          next: 'undo revoke',
          save: 'save',
          prettier: 'prettier',
          pageFullscreen: 'fullscreen in page',
          fullscreen: 'fullscreen',
          preview: 'preview',
          previewOnly: 'previewOnly',
          htmlPreview: 'html preview',
          catalog: 'catalog',
          github: 'source code',
        },
        titleItem: {
          h1: 'Lv1 Heading',
          h2: 'Lv2 Heading',
          h3: 'Lv3 Heading',
          h4: 'Lv4 Heading',
          h5: 'Lv5 Heading',
          h6: 'Lv6 Heading',
        },
        imgTitleItem: {
          link: 'Add Img Link',
          upload: 'Upload Img',
          clip2upload: 'Clip Upload',
        },
        linkModalTips: {
          linkTitle: 'Add Link',
          imageTitle: 'Add Image',
          descLabel: 'Desc:',
          descLabelPlaceHolder: 'Enter a description...',
          urlLabel: 'Link:',
          urlLabelPlaceHolder: 'Enter a link...',
          buttonOK: 'OK',
        },
        clipModalTips: {
          title: 'Crop Image',
          buttonUpload: 'Upload',
        },
        copyCode: {
          text: 'Copy',
          successTips: 'Copied!',
          failTips: 'Copy failed!',
        },
        mermaid: {
          flow: 'flow',
          sequence: 'sequence',
          gantt: 'gantt',
          class: 'class',
          state: 'state',
          pie: 'pie',
          relationship: 'relationship',
          journey: 'journey',
        },
        katex: {
          inline: 'inline',
          block: 'block',
        },
        footer: {
          markdownTotal: 'Word Count',
          scrollAuto: 'Scroll Auto',
        },
      },
    },
  },
});

🍘 mermaidTemplate

js Copy
import { config } from 'md-editor-v3';

config({
  editorConfig: {
    // mermaid template
    mermaidTemplate: {
      flow: `flow tempalte`,
      sequence: `sequence template`,
      gantt: `gantt template`,
      class: `class template`,
      state: `state template`,
      pie: `pie template`,
      relationship: `relationship template`,
      journey: `journey template`,
    },
  },
});

🍥 renderDelay

js Copy
import { config } from 'md-editor-v3';

config({
  editorConfig: {
    // delay rendering time(ms)
    renderDelay: 0,
  },
});

🍥 zIndex

js Copy
import { config } from 'md-editor-v3';

config({
  editorConfig: {
    // for modal component
    zIndex: 2000,
  },
});

🥠 editorExtensions

Config some dependency libraries, like highlight..

typescript Copy
import { config } from 'md-editor-v3';

config({
  editorExtensions: { highlight: { js: 'https://xxx.cc' } },
});
ts Copy
export interface EditorExtensions {
  highlight?: {
    instance?: any;
    js?: string;
    css?: {
      [key: string]: {
        light: string;
        dark: string;
      };
    };
  };
  prettier?: {
    // >= 2.2.0
    prettierInstance?: any;
    parserMarkdownInstance?: any;

    standaloneJs?: string;
    parserMarkdownJs?: string;
  };
  cropper?: {
    instance?: any;
    js?: string;
    css?: string;
  };
  screenfull?: {
    instance?: any;
    js?: string;
  };
  mermaid?: {
    instance?: any;
    js?: string;
  };
  katex?: {
    instance?: any;
    js?: string;
    css?: string;
  };
}

🥠 editorExtensionsAttrs

Synchronously add attributes to the CDN link tags, consistent with the type of editorExtensions, with a value type of HTMLElementTagNameMap['tagName'].

js Copy
import { config } from 'md-editor-v3';

config({
  editorExtensionsAttrs: {
    highlight: {
      js: {
        className: 'hglh-js',
      },
      css: {
        atom: {
          light: {
            className: 'atom-light-css',
          },
          dark: {
            className: 'atom-dark-css',
          },
        },
      },
    },
  },
});

Example of using built-in basic configuration:

js Copy
import { config, editorExtensionsAttrs } from 'md-editor-v3';

config({
  editorExtensionsAttrs,
});

Warning

Do not attempt to define the src \ onload \ id of the script and rel \ href \ id of the link in editorExtensionsAttrs, as they will be overwritten by default values


🎨 mermaidConfig

Configure mermaid, Details

js Copy
import { config } from 'md-editor-v3';
config({
  mermaidConfig(base: any) {
    return {
      ...base,
      logLevel: 'error',
    };
  },
});

🔧 katexConfig

Configure katex, Details

js Copy
import { config } from 'md-editor-v3';

config({
  katexConfig(base: any) {
    return {
      ...base,
      strict: false,
    };
  },
});

🪡 Shortcut keys

Pay attention

Shortcut keys are only available when the textarea has received focus!

key function description
TAB insert space Insert space, the length eq tabWidth, default: 2, support multiline
SHIFT + TAB delete space, setting is the same as Tab
CTRL + C copy When selected, copy the selected content. When not selected, copy the content of the current line
CTRL + X shear When selected, cut the selected content. When not selected, cut the current line
CTRL + D delete When selected, delete the selected content. When not selected, delete the current line
CTRL + S save Trigger onSave event
CTRL + B bold text **bold**
CTRL + U underline <u>underline</u>
CTRL + I italic *italic*
CTRL + 1-6 h1-h6 # title
CTRL + ↑ superscript <sup>superscript</sup>
CTRL + ↓ subscript <sub>subscript</sub>
CTRL + O ordered list 1. ordered list
CTRL + L link [link](https://github.com/imzbf/md-editor-v3)
CTRL + Z withdraw Withdraw history in editor, not the function of system
CTRL + F find and replace
CTRL + SHIFT + S line-through ~line-through~
CTRL + SHIFT + U unordered list - unordered list
CTRL + SHIFT + C code block
CTRL + SHIFT + I picture ![picture](https://github.com/imzbf)
CTRL + SHIFT + Z forward Forward history in editor, not the function of system
CTRL + SHIFT + F Beautify
CTRL + ALT + C code row
CTRL + SHIFT + ALT + T table |table|

🪤 Internal Components

On-demand import, eg: import { DropdownToolbar } from 'md-editor-v3'.

Built-in attribute

To help developers quickly insert content and use editor attributes, the editor component has already added the following property values to the extension components in the header toolbar and footer toolbar by default(If you provide it as well, your content will be given priority), More detailed reference examples: ExportPDF

Name defToolbars defFooters
insert ×
theme
previewtheme ×
codeTheme ×
language
disabled

Example:

vue Copy
<!-- HeaderTool.vue -->
<template>
  <NormalToolbar>Content</NormalToolbar>
</template>
<script setup>
const props = defineProps({
  theme: {
    type: String,
  },
  insert: {
    type: Function,
  },
  ...
});
console.log('==', props);
// == { insert: (...)=> {...}, theme: 'light', ... }
</script>

<!-- MyEditor1.vue -->
<template>
  <MdEditor :toolbars="toolbars">
    <template #defToolbars>
      <HeaderTool key="key" />
    </template>
  </MdEditor>
</template>
<script setup>
const toolbars = [0];
</script>

<!-- =================================== -->

<!-- FooterTool.vue -->
<template>
  <NormalFooterToolbar>Content</NormalFooterToolbar>
</template>

<script setup>
const props = defineProps({
  theme: {
    type: String,
  },
  language: {
    type: String,
  },
  disabled: {
    type: Boolean,
  },
});
console.log('==', props);
// == { theme: 'light', disabled: false, language: 'zh-CN' }
</script>

<!-- MyEditor2.vue -->
<template>
  <MdEditor :footers="footers">
    <template #defFooters>
      <HeaderTool key="key" />
    </template>
  </MdEditor>
</template>
<script setup>
const footers = [0];
</script>

🐣 NormalToolbar

  • props

    • title: string, not required, title of toolbar.
  • events

    • onClick: (e: MouseEvent) => void, required.
  • slots

    • default: any, not required, it is usually an icon, which is displayed on the toolbar.
    • trigger: string | VNode, not required, deprecated, as above.

usage:

vue Copy
<template>
  <NormalToolbar title="mark" @onClick="handler">
    <svg class="md-editor-icon" aria-hidden="true">
      <use xlink:href="#icon-mark"></use>
    </svg>
  </NormalToolbar>
</template>

<script setup lang="ts">
import { PropType } from 'vue';
import { NormalToolbar } from 'md-editor-v3';
import type { Insert } from 'md-editor-v3';

const props = defineProps({
  /**
   * `insert` will be automatically injected into the component by the editor
   */
  insert: {
    type: Function as PropType<Insert>,
    default: () => {
      //
    },
  },
});

const handler = () => {
  props.insert((selectedText) => {
    /**
     * targetValue    Content to be inserted
     * select         Automatically select content, default: true
     * deviationStart Start position of the selected content, default: 0
     * deviationEnd   End position of the selected content, default: 0
     */
    return {
      targetValue: `==${selectedText}==`,
      select: true,
      deviationStart: 0,
      deviationEnd: 0,
    };
  });
};
</script>
vue Copy
<template>
  <MdEditor v-model="text" :toolbars="toolbars">
    <template #defToolbars>
      <MyToolbar />
    </template>
  </MdEditor>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { MdEditor } from 'md-editor-v3';
import MyToolbar from './MyToolbar.vue';
import 'md-editor-v3/lib/style.css';

const text = ref('');
const toolbars = ['bold', 0, 'github'];
</script>

MarkExtension Source Code


  • props

    • title: string, not required, title of toolbar.
    • visible: boolean, required.
  • events

    • onChange: (visible: boolean) => void, required.
  • slots

    • default: any, not required, it is usually an icon, which is displayed on the toolbar.
    • trigger: string | VNode, not required, deprecated, as above.
    • overlay: string | VNode, required, content of dropdown box.
vue Copy
<template>
  <DropdownToolbar title="emoji" :visible="visible" :onChange="onChange">
    <template #overlay>
      <div class="emoji-container">
        <ol class="emojis">
          <li
            v-for="(emoji, index) of emojis"
            :key="`emoji-${index}`"
            @click="handler(emoji)"
            v-text="emoji"
          ></li>
        </ol>
      </div>
    </template>
    <svg class="md-editor-icon" aria-hidden="true">
      <use xlink:href="#icon-emoji"></use>
    </svg>
  </DropdownToolbar>
</template>

<script setup lang="ts">
import { PropType, ref } from 'vue';
import { DropdownToolbar } from 'md-editor-v3';
import type { Insert } from 'md-editor-v3';

const emojis = ['😀', '😃'];

const props = defineProps({
  /**
   * `insert` will be automatically injected into the component by the editor
   */
  insert: {
    type: Function as PropType<Insert>,
    default: () => {
      //
    },
  },
});

const visible = ref(false);

const onChange = (_visible: boolean) => {
  visible.value = _visible;
};

const handler = (emoji: any) => {
  props.insert(() => {
    /**
     * targetValue    Content to be inserted
     * select         Automatically select content, default: true
     * deviationStart Start position of the selected content, default: 0
     * deviationEnd   End position of the selected content, default: 0
     */
    return {
      targetValue: emoji,
      select: true,
      deviationStart: 0,
      deviationEnd: 0,
    };
  });
};
</script>
vue Copy
<template>
  <MdEditor v-model="text" :toolbars="toolbars">
    <template #defToolbars>
      <MyToolbar />
    </template>
  </MdEditor>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { MdEditor } from 'md-editor-v3';
import MyToolbar from './MyToolbar.vue';
import 'md-editor-v3/lib/style.css';

const text = ref('');
const toolbars = ['bold', 0, 'github'];
</script>

EmojiExtension Source Code


🦉 ModalToolbar

  • props

    • title: string, not required, title of toolbar.
    • visible: boolean, required, visibility of Modal.
    • width: string, not required, width of Modal, default auto.
    • height: string, same as width.
    • showAdjust: boolean, not required, visibility of fullscreen button.
    • isFullscreen: boolean, required when showAdjust = true, status of fullscreen.
    • class: string, ^4.16.8, not required.
    • style: CSSProperties | string, ^4.16.8, not required.
    • showMask: boolean, ^4.16.8, not required, whether to display the mask layer, default true.
  • events

    • onClick: () => void, required.
    • onClose: () => void, required, close event.
    • onAdjust: (val: boolean) => void, fullscreen button click event.
  • slots

    • modalTitle: string | VNode, not required, title of the Modal.
    • trigger: string | VNode, required, it is usually an icon, which is displayed on the toolbar.
    • default: any, not required, content of Modal.
vue Copy
<template>
  <ModalToolbar
    :visible="data.modalVisible"
    :isFullscreen="data.modalFullscreen"
    showAdjust
    title="Preview"
    modalTitle="Page Preview"
    width="870px"
    height="600px"
    @onClick="data.modalVisible = true"
    @onClose="data.modalVisible = false"
    @onAdjust="data.modalFullscreen = !data.modalFullscreen"
  >
    <button @click="handler">Click me</button>
    <template #trigger>
      <svg class="md-editor-icon" aria-hidden="true">
        <use xlink:href="#icon-read"></use>
      </svg>
    </template>
  </ModalToolbar>
</template>

<script setup lang="ts">
import { PropType, reactive } from 'vue';
import { ModalToolbar } from 'md-editor-v3';
import type { Insert } from 'md-editor-v3';

const data = reactive({
  modalVisible: false,
  modalFullscreen: false,
});

const props = defineProps({
  /**
   * `insert` will be automatically injected into the component by the editor
   */
  insert: {
    type: Function as PropType<Insert>,
    default: () => {
      //
    },
  },
});

const handler = () => {
  props.insert((selectedText) => {
    /**
     * targetValue    Content to be inserted
     * select         Automatically select content, default: true
     * deviationStart Start position of the selected content, default: 0
     * deviationEnd   End position of the selected content, default: 0
     */
    return {
      targetValue: `==${selectedText}==`,
      select: true,
      deviationStart: 0,
      deviationEnd: 0,
    };
  });
};
</script>
vue Copy
<template>
  <MdEditor v-model="text" :toolbars="toolbars">
    <template #defToolbars>
      <MyToolbar />
    </template>
  </MdEditor>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { MdEditor } from 'md-editor-v3';
import MyToolbar from './MyToolbar.vue';
import 'md-editor-v3/lib/style.css';

const text = ref('');
const toolbars = ['bold', 0, 'github'];
</script>

ExportPDF Source Code


🐻 MdCatalog

  • props

    • editorId: string, required, editor's id, used to register listening events.
    • class: string, not required.
    • mdHeadingId: mdHeadingId, not required, same as editor.
    • scrollElement: string | HTMLElement, not required, it is an element selector when its type is string. When previewOnly eq true, it is usually set to document.documentElement.
    • theme: 'light' | 'dark', not required, provide it when you want to change theme online, it is the same as Editor theme.
    • offsetTop: number, not required, highlight current item of catalogs when title is offsetTop pixels from the top, default 20.
    • scrollElementOffsetTop: number, not required, offsetTop of the scroll container, default 0.
  • events

    • onClick: (e: MouseEvent, t: TocItem) => void, not required.
    • onActive: (heading: HeadList | undefined) => void, not required, heading was highlighted.

usage:

vue Copy
<template>
  <!-- Ensure that the editorId is the same -->
  <MdPreview :id="state.id" :modelValue="state.text" :theme="state.theme" />
  <MdCatalog
    :editorId="state.id"
    :scrollElement="scrollElement"
    :theme="state.theme"
  />
</template>

<script setup>
import { reactive } from 'vue';
import { MdPreview, MdCatalog } from 'md-editor-v3';
import 'md-editor-v3/lib/preview.css';

const state = reactive({
  theme: 'dark',
  text: 'heading',
  id: 'my-editor',
});

const scrollElement = document.documentElement;
</script>

🛸 MdModal

It is usually used in conjunction with DropdownToolbar.

  • props

    • visible: boolean, required, visibility of Modal.
    • width: string, not required, width of Modal, default auto.
    • height: string, same as width.
    • showAdjust: boolean, not required, visibility of fullscreen button.
    • isFullscreen: boolean, required when showAdjust = true, status of fullscreen.
    • class: string, not required.
    • style: CSSProperties | string, not required.
    • showMask: boolean, ^4.16.8, not required, whether to display the mask layer, default true.
  • events

    • onClose: () => void, required, close event.
    • onAdjust: (val: boolean) => void, fullscreen button click event.
  • slots

    • title: string | VNode, not required, title of Modal.
    • default: any, not required, content of Modal.
vue Copy
<template>
  <DropdownToolbar title="emoji" :visible="state.visible" :onChange="onChange">
    <template #overlay>
      <ul>
        <li @click="state.mVisible = true">option 1</li>
        <li>option 2</li>
      </ul>
    </template>
    <template #trigger>
      <svg class="md-editor-icon" aria-hidden="true">
        <use xlink:href="#icon-emoji"></use>
      </svg>
    </template>
  </DropdownToolbar>

  <MdModal title="title" :visible="state.mVisible" @onClose="onClose">
    Content, Content
  </MdModal>
</template>

<script setup lang="ts">
import { reactive } from 'vue';
import { DropdownToolbar, MdModal } from 'md-editor-v3';

const state = reactive({
  visible: false,
  mVisible: false,
});

const onClose = () => {
  state.mVisible = false;
};

const onChange = (_visible: boolean) => {
  visible.value = _visible;
};
</script>

🛸 NormalFooterToolbar

  • events

    • onClick: (e: MouseEvent) => void, not required, toolbar was clicked.
  • slots

    • default: any, required, content.
vue Copy
<!-- FooterTool.vue -->
<template>
  <NormalFooterToolbar>Content</NormalFooterToolbar>
</template>

<script>
import { MdEditor, NormalFooterToolbar } from 'md-editor-v3';
</script>

<!-- MyEditor.vue -->

<template>
  <MdEditor :footers="footers">
    <template #defFooters>
      <FooterTool key="key" />
    </template>
  </MdEditor>
</template>

<script setup>
import { MdEditor, NormalFooterToolbar } from 'md-editor-v3';

const footers = [0];
</script>

🪤 Internal Configuration

js Copy
import {
  allToolbar,
  allFooter,
  zh_CN,
  en_US,
  editorExtensionsAttrs,
} from 'md-editor-v3';

console.log(allToolbar, allFooter, zh_CN, en_US, editorExtensionsAttrs);

📦 Internal Tools

🧹 clearSideEffects

>=5.0.0

Clear the side effects brought by the component, for example: links embedded using CDN. To ensure that multiple components can run correctly., the component will not actively remove these when it is unmounted.

js Copy
import { clearSideEffects } from 'md-editor-v3';

clearSideEffects();

It will remove the CDN references in the page. If the component instance still exists on the current page, do not call it!

XSSPlugin

>=5.0.0

Example: Add XSS extension

✍️ Edit This Page

doc-en-US