DEV Community

Cover image for wangEditor - Vue 3 Rich Text Editor (w/ Typescript)
cn-2k
cn-2k

Posted on

wangEditor - Vue 3 Rich Text Editor (w/ Typescript)

In this article I'll show an interesting rich text editor that I found for Vue 3 and how to implement it in your next Vue 3 App.

wangEditor 5 - Open source web rich text editor, run right out of the box, config simply.


1 - Install the dependencies:

Editor package:

yarn add @wangeditor/editor
# npm install @wangeditor/editor --save
Enter fullscreen mode Exit fullscreen mode

Vue 3.x editor component:

yarn add @wangeditor/editor-for-vue@next
# npm install @wangeditor/editor-for-vue@next --save
Enter fullscreen mode Exit fullscreen mode

In order to start using the editor we need to understand a few things before:

  • In this case @wangeditor/editor will serve us some Typescript interfaces for typing our editor instance and more functionalities (read more on wangEditor docs).

  • The @wangeditor/editor-for-vue will serve us the Toolbar and Editor components for use on a Vue 3 App.

2 - Coding the script and style

Let's start creating a component called wangEditor.vue and implementing the script and style sections.

@/components/wangEditor.vue

<template>
</template>

<script setup lang="ts">
import { onBeforeUnmount, shallowRef, reactive, toRefs } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import {
  IDomEditor,
  IEditorConfig,
  IToolbarConfig,
} from "@wangeditor/editor";

const props = defineProps<{
  modelValue: string;
}>();

const emit = defineEmits<{
  (e: "update:modelValue", value: string): void;
}>();

// Editor instance shallowRef must be used
const editorRef = shallowRef<IDomEditor>();

const state = reactive({
  toolbarConfig: {} as IToolbarConfig,
  editorConfig: {
    placeholder: "Write something...",
    customAlert: () => {},
    scroll: true,
    readOnly: false,
    autoFocus: true,
    hoverbarKeys: {},
  } as IEditorConfig,
  defaultHtml: props.modelValue,
  mode: "default",
});

const { toolbarConfig, editorConfig, defaultHtml, mode } = toRefs(state);

const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor;
};

function handleChange(editor: IDomEditor) {
  emit("update:modelValue", editor.getHtml());
}

// When the component is destroyed, the editor is also destroyed in time.
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
</script>

<style src="@wangeditor/editor/dist/css/style.css"></style>
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. Imports necessary functions and types from Vue and WangEditor libraries.
  2. Defines component props using defineProps for a model value.
  3. Defines component emits using defineEmits for updating the model value.
  4. Initializes a shallowRef for the WangEditor instance (editorRef).
  5. Defines a reactive state object (state) containing configurations for the toolbar, editor, default HTML content, and mode (refer to wangEditor doc website).
  6. Uses toRefs to create individual refs for the properties of the state object.
  7. Defines a function (handleCreated) to be called when the editor is created, storing the editor instance in editorRef.
  8. Defines a function (handleChange) to be called when the editor content changes, emitting an update to the model value.
  9. Uses onBeforeUnmount to destroy the editor instance when the component is about to be unmounted.
  10. Imports the WangEditor styles on <style> tag src prop.

3 - Coding the template (using wangEditor Vue Components)

@/components/wangEditor.vue

<template>
  <div
    style="border: 1px solid gray"
  >
    <Toolbar
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      style="border-bottom: 1px solid gray;"
      :mode="mode"
    />
    <Editor
      :defaultConfig="editorConfig"
      v-model="defaultHtml"
      @on-change="handleChange"
      style="height: 300px; overflow-y: hidden; border-radius: 20px"
      :mode="mode"
      @on-created="handleCreated"
    />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode
  1. <Toolbar> represents the top part of editor, all text formatter functions are here.
  2. <Editor> represents the textarea section.
  3. Each component has its own props and methods, so we simply need to bind them.

Fullcode:

<template>
  <div
    style="border: 1px solid gray"
  >
    <Toolbar
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      style="border-bottom: 1px solid gray;"
      :mode="mode"
    />
    <Editor
      :defaultConfig="editorConfig"
      v-model="defaultHtml"
      @on-change="handleChange"
      style="height: 300px; overflow-y: hidden; border-radius: 20px"
      :mode="mode"
      @on-created="handleCreated"
    />
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, shallowRef, reactive, toRefs } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import {
  IDomEditor,
  IEditorConfig,
  IToolbarConfig,
} from "@wangeditor/editor";

const props = defineProps<{
  modelValue: string;
}>();

const emit = defineEmits<{
  (e: "update:modelValue", value: string): void;
}>();

// Editor instance shallowRef must be used
const editorRef = shallowRef<IDomEditor>();

const state = reactive({
  toolbarConfig: {} as IToolbarConfig,
  editorConfig: {
    placeholder: "Write something...",
    customAlert: () => {},
    scroll: true,
    readOnly: false,
    autoFocus: true,
    hoverbarKeys: {},
  } as IEditorConfig,
  defaultHtml: props.modelValue,
  mode: "default",
});

const { toolbarConfig, editorConfig, defaultHtml, mode } = toRefs(state);

const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor;
};

function handleChange(editor: IDomEditor) {
  emit("update:modelValue", editor.getHtml());
}

// When the component is destroyed, the editor is also destroyed in time.
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
</script>

<style src="@wangeditor/editor/dist/css/style.css"></style>

Enter fullscreen mode Exit fullscreen mode

How to exclude some menus from Toolbar?

On toolbarConfig object we can pass a excludeKeys array containing the keys of the menu items we want to remove:

  toolbarConfig: {
    excludeKeys: [
      "headerSelect",
      "group-more-style",
      "fontFamily",
      "lineHeight",
      "group-indent",
      "insertLink",
      "group-image",
      "group-video",
      "insertTable",
      "codeBlock",
      "fullScreen",
    ],
  } as IToolbarConfig,
Enter fullscreen mode Exit fullscreen mode

Refer to https://www.wangeditor.com/en/v5/toolbar-config.html#excludekeys for more info!

How to exclude some menus from editor Hoverbar?

On the editorConfig object, we can pass a text object with a menuKeys array, specifying only the keys we want on the Hover Bar:

  editorConfig: {
    placeholder: "Write something...",
    customAlert: () => {},
    scroll: true,
    readOnly: false,
    autoFocus: true,
    hoverbarKeys: {
      text: {
        menuKeys: [
          "blockquote",
          "bold",
          "through",
          "italic",
          "color",
          "bgColor",
          "bulletedList",
          "numberedList",
          "clearStyle",
        ],
      },
    },
  } as IEditorConfig,
Enter fullscreen mode Exit fullscreen mode

Refer to https://www.wangeditor.com/en/v5/editor-config.html for more info!

Usage

Now you just need to import your component inside any Vue file:

@/views/EditorPage.vue

<template>
 <div>
   <WangEditor v-model="text" />
 </div>
<template>

<script setup lang="ts">
import { ref } from 'vue'
import WangEditor from '@/components/wangEditor.vue'

const text = ref<string>("")
</script>

Enter fullscreen mode Exit fullscreen mode

That's it!

Top comments (2)

Collapse
 
malwick profile image
bata humphrey

how do you change the chiness writing to englsih
on the toolbar

Collapse
 
marc_figa_60e5a49f5e55e81 profile image
Marc Figa