---
title: Integrate a Third-Party Rich Content Editor
product: Survey Creator
description: Learn how to transform text entry fields within the Property Grid into powerful rich text editors for easy and precise text formatting. View this free demo to explore the capabilities of a WYSIWYG visual editor and access a code example for JavaScript to discover how to seamlessly integrate Quill into your SurveyJS form-building tool.
framework: Vue 3
source: https://surveyjs.io/survey-creator/examples/form-builder-with-integrated-rich-text-editor/vue3js
index: https://surveyjs.io/survey-creator/examples/overview.md
---

# Integrate a Third-Party Rich Content Editor (Vue 3)

In addition to multiple configuration options available by default, SurveyJS Creator supports various customizations. For instance, you can replace text entry fields within the Property Grid (the input fields you use to enter a title or form description) with dedicated rich text editors. A rich text editor is a WYSIWYG visual editor that provides an input area for editing your form's content and a toolbar equipped with all the necessary formatting tools. Survey creators can apply bold, italic, or underline font style to text, add bullet points or numbered lists, insert hyperlinks, adjust text alignment, and more. This demo illustrates how to integrate a third-party <a href="https://quilljs.com/" target="_blank">Quill</a> text editor into Survey Creator.

For a step-by step Quill integration tutorial, refer to the following documentation articles. Although they describe integration of a color picker, the same instructions apply to any other third-party component, including Quill. 

- [Integrate Third-Party React Components](https://surveyjs.io/form-library/documentation/customize-question-types/third-party-component-integration-react)
- [Integrate Third-Party Angular Components](https://surveyjs.io/form-library/documentation/customize-question-types/third-party-component-integration-angular)
- [Integrate Third-Party Vue 3 Components](/form-library/documentation/customize-question-types/third-party-component-integration-vue)

## Files

### `public/index.html`

```html
<div id="app" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0;"></div>
```

### `src/Quill.vue`

```html
<template>
  <quill-editor
    :style="{ height: question.height }"
    v-model:value="question.value"
    :disabled="question.isReadOnly"
    :options="quillOptions"
  />
</template>
<script setup lang="ts">
import { useQuestion } from "survey-vue3-ui";
import { ref } from "vue";
import { QuestionQuillModel } from "./QuillModel";

const quillOptions = {
  theme: "snow",
  modules: {
    toolbar: [[{ "header": [1, 2, 3, false] }], ["bold", "italic", "underline", "link"], [{ "list": "ordered" }, { "list": "bullet" }], ["clean"]]
  }
};
const root = ref(null);
const props = defineProps<{ question: QuestionQuillModel }>();

useQuestion(props, root);
</script>
```

### `src/QuillModel.ts`

```ts
import { Question, Serializer, ElementFactory } from "survey-core";
import { PropertyGridEditorCollection } from "survey-creator-core";

// Must use lowercase
const CUSTOM_TYPE = "quill";

// Create a question model
export class QuestionQuillModel extends Question {
    getType() {
        return CUSTOM_TYPE;
    }
    get height(): string {
        return this.getPropertyValue("height");
    }
    set height(val: string) {
        this.setPropertyValue("height", val);
    }
}

// Register the model in `ElementFactory`
ElementFactory.Instance.registerElement(CUSTOM_TYPE, (name) => {
    return new QuestionQuillModel(name);
});

// Add question type metadata for further serialization into JSON
Serializer.addClass(
    CUSTOM_TYPE,
    [{ name: "height", default: "200px", category: "layout" }],
    function () {
        return new QuestionQuillModel("");
    },
    "question"
);

// Register `quill` as an editor for properties of the `text` and `html` types in the Survey Creator's Property Grid
PropertyGridEditorCollection.register({
    fit: function (prop) {
        return prop.type == "text" || prop.type == "html";
    },
    getJSON: function () {
        return { type: "quill" };
    }
});
```

### `src/App.vue`

```html
<template>
    <SurveyCreatorComponent :model="creator" />
</template>
<script setup lang="ts">
    import { SurveyCreatorModel } from "survey-creator-core";
    import { SurveyCreatorComponent } from "survey-creator-vue";
    import { getLocaleStrings } from "survey-creator-core";
    import "survey-core/survey.i18n";
    import "survey-creator-core/survey-creator-core.i18n";
    import "survey-core/survey-core.css";
    import "survey-creator-core/survey-creator-core.css";
    import "./index.css";
    import SurveyTheme from "survey-core/themes";
    import { registerCreatorTheme } from "survey-creator-core";

    registerCreatorTheme(SurveyTheme); // Add predefined Survey Creator UI themes

    function applyHtml(_, options) {
        let str = options.text;
        if (str.indexOf("<p>") === 0) {
            // Remove root paragraphs <p></p>
            str = str.substring(3);
            str = str.substring(0, str.length - 4);
        }
        // Set HTML markup to render
        options.html = str;
    }
    
    // Specify a title for the toolbox category that will contain the Quill question type  
    const translations = getLocaleStrings("en");
    translations.toolboxCategories["custom"] = "Custom Questions";
    const creator = new SurveyCreatorModel();
    // Move the Quill question type to the first position in the Toolbox
    const toolboxItems = creator.toolbox.items;
    const quillIndex = toolboxItems.findIndex((item) => item.name === "quill");
    const quillItem = toolboxItems.splice(quillIndex, 1)[0];
    quillItem.title = "Rich Text Editor";
    quillItem.iconName = "icon-comment";
    toolboxItems.unshift(quillItem);
    creator.toolbox.changeCategory("quill", "custom");
    
    // Apply HTML markup to survey contents
    creator.survey.onTextMarkdown.add(applyHtml);
    creator.onSurveyInstanceSetupHandlers.add((_, options) => {    
        options.survey.onTextMarkdown.add(applyHtml);    
    });
    
    creator.JSON = {
        "title": "Quill Integration with SurveyJS",
        "description": "<ul><li><strong>Bold</strong></li><li><em>Italics</em></li><li><s>Strikethrough</s></li></ul>",
        "pages": [{
            "name": "page1",
            "elements": [{
                "type": "quill",
                "name": "rich-text-editor",
                "title": "Rich Text Editor",
                "defaultValue": "Hello world!"
            }]
        }]
    }
    
</script>
```

### `src/index.css`

```css
.ql-toolbar.ql-snow {
    white-space: normal;
}
.sv-string-editor--html {
    white-space: normal !important;
}
.quill .ql-container {
    max-height: calc(100% - 42px);
}
```

### `src/main.ts`

```ts
import { createApp } from "vue";
import App from "./App.vue";
import { quillEditor } from "vue3-quill";
export * from "./QuillModel";
import Quill from "./Quill.vue";

const app = createApp(App);
app.use(quillEditor);
app.component("survey-quill", Quill);
app.mount("#app");
```

### `src/shims-vue.d.ts`

```ts
/* eslint-disable */
declare module "*.vue" {
    import type { DefineComponent } from "vue"
    const component: DefineComponent<{}, {}, any>
    export default component
}
```

### `.eslintrc.js`

```js
module.exports = {
    root: true,
    env: {
        node: true
    },
    extends: [
        "plugin:vue/vue3-essential",
        "eslint:recommended",
        "@vue/typescript/recommended",
        "@vue/prettier",
        "@vue/prettier/@typescript-eslint"
    ],
    parserOptions: {
        ecmaVersion: 2020
    },
    rules: {
        "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
        "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
    },
    overrides: [
        {
            files: [
                "**/__tests__/*.{j,t}s?(x)",
                "**/tests/unit/**/*.spec.{j,t}s?(x)"
            ],
            env: {
                jest: true
            }
        }
    ]
};
```

### `babel.config.js`

```js
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"]
};
```

### `package.json`

```json
{
  "name": "surveyjs-library-vue3",
  "version": "0.1.0",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "tslib": "2.6.1",
    "vue": "^3.4.1",
    "vue3-quill": "latest",
    "survey-core": "latest",
    "survey-vue3-ui": "latest",
    "survey-creator-core": "latest",
    "survey-creator-vue": "latest",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-pwa": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "@vue/test-utils": "^2.0.0-0",
    "eslint": "^6.7.2",
    "eslint-plugin-prettier": "^3.1.3",
    "eslint-plugin-vue": "^7.0.0-0",
    "node-sass": "^4.12.0",
    "prettier": "^1.19.1",
    "sass-loader": "^8.0.2",
    "typescript": "~3.9.3"
  }
}
```

### `tsconfig.json`

```json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env",
      "jest"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/survey-creator/examples/form-builder-with-integrated-rich-text-editor/angular.md)
- [React](https://surveyjs.io/survey-creator/examples/form-builder-with-integrated-rich-text-editor/reactjs.md)
- [jQuery](https://surveyjs.io/survey-creator/examples/form-builder-with-integrated-rich-text-editor/jquery.md)
