Library / SDK
davidroyer/vue2-editor avatar
davidroyer/vue2-editor

vue2-editor: a Quill wrapper for Vue 2 projects that are not migrating yet

A text editor using Vue.js and Quill

2,512 stars353 forksJavaScriptMIT

At a glance

What is it?
vue2-editor packages Quill.js as a Vue 2 component with v-model binding, a configurable toolbar and a custom image handler. It is a maintenance-mode choice for apps already on Vue 2, and an awkward one for anyone starting on Vue 3.
Who is it for?
Adopt vue2-editor if your application is already on Vue 2 and you want Quill's toolbar and delta model behind a single component with v-model binding. Do not adopt it for a new Vue 3 codebase: the package name, the import path and the Nuxt module are all written for Vue 2, and the related searches show people asking about a Vue 3 version.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap vue2-editor fills between Quill and a Vue 2 component tree

Quill is a standalone JavaScript editor. It owns a DOM node, exposes a delta-based document model, and expects you to wire up initialization, teardown and content synchronization yourself. In a Vue 2 application that means writing a wrapper component, tracking the editor instance outside of reactive state, and deciding when to push content in and when to read it out. vue2-editor is that wrapper, published as a package. It exports a VueEditor component plus the underlying Quill object, so the same import can give you a ready-made editor or a handle for registering custom modules.

The audience is narrow and specific: teams with an existing Vue 2 application that need rich text input and do not want to hand-roll the Quill lifecycle. The package.json describes it as an HTML editor using Vue.js 2 and Quill.js. The version field in package.json is 2.10.3, while the most recent tagged releases listed are 2.6.6, 2.6.5 and 2.6.4, all dated 2018-08-04. That gap between the published package version and the release list is worth noting before you assume the changelog tells the whole story.

The repository is not archived. The last push was on 2026-09-26, which is two days before the date used for this review. That recency does not by itself mean the component API has moved on: the newest tagged release in the list is from 2018, so the surface documented in the README should be treated as stable rather than evolving.

How the VueEditor component talks to Quill

The component owns a container element and mounts a Quill instance into it. Content flows in both directions through v-model: you bind a string property, and the component keeps that string in sync with the editor's HTML. The README's basic example sets data() { return { content: "<h1>Some initial content</h1>" } } and binds it, which is the whole integration for the common case.

Configuration is split across several props rather than one options object. editorOptions merges into the default Quill config, which is where you add formats or register custom Quill modules. customModules declares Quill modules to register. editorToolbar replaces the built-in toolbar, and the README notes the default toolbar array is too long to reproduce in its props table, pointing instead at a toolbar example further down. placeholder and disabled are self-explanatory. id defaults to quill-container and the README states it is necessary when you place multiple editors in the same view, because two components sharing a default DOM id would collide.

Events mirror Quill's own: blur and focus pass the quill instance, selection-change passes range, oldRange and source, and text-change passes delta, oldDelta and source. If you already know Quill's event signatures, there is nothing new to learn here, which is the point of the wrapper.

Installing vue2-editor and rendering a first editor

The README gives two package managers. Both install the same package, so pick whichever your lockfile already uses.

bash
npm install vue2-editor

The yarn alternative is `yarn add vue2-editor`. After installation, the basic use case imports only the component. The advanced import also pulls in Quill, which you need when registering custom modules or formats.

javascript
// Basic Use - Covers most scenarios
import { VueEditor } from "vue2-editor";

// Advanced Use - Hook into Quill's API for Custom Functionality
import { VueEditor, Quill } from "vue2-editor";

A minimal single-file component then registers VueEditor locally and binds a string. The README's basic setup example is the shortest path to a working editor.

vue
<template>
  <div id="app">
    <vue-editor v-model="content"></vue-editor>
  </div>
</template>

<script>
import { VueEditor } from "vue2-editor";

export default {
  components: { VueEditor },
  data() {
    return { content: "<h1>Some initial content</h1>" };
  }
};
</script>

When this renders you should see a Quill toolbar above an editable area pre-filled with the heading. Typing updates the content property, and assigning a new string to content replaces the editor's contents, which is the pattern the README's set-contents example demonstrates with a button that assigns htmlForEditor = "<h1>Html For Editor</h1>".

In Nuxt, the README says to add the module to the modules array in nuxt.config.js, and to wrap the component in client-only to avoid Vue warnings about a content mismatch.

javascript
{
  modules: ["vue2-editor/nuxt"];
}
html
<client-only>
  <VueEditor />
</client-only>

The client-only wrapper is not optional decoration. Quill needs a browser DOM, so server-side rendering of the editor produces a mismatch unless you defer it to the client.

The image handler is the part you have to design yourself

By default, pasting or inserting an image converts it to Base64 and inlines it in the HTML string. The README documents useCustomImageHandler as the escape hatch: set it to true and the component stops doing that conversion, instead emitting image-added with three parameters. The file, the Editor instance, and the cursor position at the time of upload.

The README's example posts a FormData object to a URL, reads result.data.url from the response, then calls Editor.insertEmbed(cursorLocation, "image", url) and resetUploader(). Two details matter here. First, the cursor position is captured at selection time and passed to you, because by the time your upload resolves the user may have clicked elsewhere; inserting at the live cursor would put the image in the wrong place. Second, the README's method signature in the example includes a fourth parameter, resetUploader, even though the prose above the example says three parameters are passed. The example is the more complete reference; the prose is out of step with it.

There is a companion repository, linked from the README, that demonstrates the handler against an actual server. The README does not document retry behaviour, upload progress, or what happens if the user deletes an image before the upload finishes. image-removed is emitted when a photo is deleted, with the same file, Editor, cursorLocation parameters, but the README does not describe how the component tracks which remote file corresponds to which embedded URL. If you need to delete the server-side asset when the user removes the image, you are building that mapping yourself.

Where vue2-editor is the wrong tool

The binding to Vue 2 is structural, not cosmetic. The package is named vue2-editor, the documented import is from vue2-editor, and the Nuxt integration is a module path, vue2-editor/nuxt. Nothing in the README describes a Vue 3 entry point, a composition API wrapper, or a migration path. The related searches include both "Vue3 editor" and "vue2 editor vue3", which suggests people are looking for exactly that and not finding it here. If your project is on Vue 3, this is not a wrapper you can drop in and adapt; the component model it targets is the options API era.

A second boundary is the release cadence. The newest tagged release in the list is 2.6.6 from 2018-08-04, while package.json carries version 2.10.3. The CHANGELOG.md is present in the repository root and the README links to it as the release notes, so the authoritative history is in that file rather than in the release list. Anyone evaluating upgrade risk should read the changelog directly instead of inferring activity from tags.

The custom image handler is a third boundary. If your product needs drag-and-drop uploads with progress indicators, retries, or automatic cleanup of orphaned assets, the component gives you an event and a cursor position, and nothing more. That is a reasonable design decision, since the package cannot know your storage backend, but it means the feature is a hook rather than a solution.

vue2-editor against Tiptap and a bare Quill integration

The closest comparison in the related searches is Tiptap, which appears as both "Tiptap vue 2" and "Tiptap editor". The approaches differ at the document model. Tiptap is built on ProseMirror and models the document as a schema-constrained tree, so extensions declare what nodes and marks are allowed and the editor enforces it. Quill, and therefore vue2-editor, uses a delta format with formats registered through editorOptions. If you need strict structural validation of content, a schema-based editor is a better fit. If you want Quill's toolbar and delta semantics inside Vue 2 with minimal glue, vue2-editor is the shorter path.

The other alternative is not a library at all: importing Quill directly and writing your own wrapper. That is what vue2-editor already is, and the trade-off is honest. You get full control over lifecycle, but you also own the v-model synchronization, the multiple-editor id handling, the Nuxt client-only deferral, and the image handler plumbing. The README shows how much code those pieces amount to, and it is not enormous. The reason to take the dependency is that someone else has already made the decisions about defaults, not that the problem is hard.

Licence, upgrade cost and what to check before adopting

The package is MIT licensed, per the license field in package.json and the LICENSE file in the repository root. MIT permits commercial use and modification with attribution and without warranty. That is a permissive baseline, but it says nothing about the licence of Quill itself or of any module you register through customModules; those are separate dependencies and you should check each one. Nothing here is legal advice.

Upgrade cost is dominated by two things. The first is the dist build: package.json defines a release script that runs standard-version, then a postbump hook that runs npm run build and commits the dist directory. That means the built output is committed to the repository, so the published artifact and the source can drift if a release is cut without the postbump step completing. The second is Quill itself. Because editorOptions merges into a default config, a Quill major version bump can change what merges cleanly, and the README does not document which Quill versions are supported.

Before adopting, read CHANGELOG.md for the entries after 2.6.6 to see what shipped between the last tagged release and the 2.10.3 in package.json. Then check the resolved Quill version in your lockfile against the toolbar configuration you plan to write, since the README's default toolbar is described as too long to list in its props table and is only shown by example.

Editorial conclusion

Adopt vue2-editor if your application is already on Vue 2 and you want Quill's toolbar and delta model behind a single component with v-model binding. Do not adopt it for a new Vue 3 codebase: the package name, the import path and the Nuxt module are all written for Vue 2, and the related searches show people asking about a Vue 3 version. Before committing, verify that the Quill version resolved by your lockfile matches what your toolbar configuration expects, and check the CHANGELOG for the release that last changed the dist build.

Frequently asked questions

How do I install vue2-editor?

Install it with npm install vue2-editor or yarn add vue2-editor, then import the VueEditor component from the package. For custom Quill modules, import Quill from the same package alongside the component.

Does vue2-editor work with Vue 3?

The README documents only Vue 2 usage: the package name is vue2-editor, the import path is vue2-editor, and the Nuxt integration is the vue2-editor/nuxt module. No Vue 3 entry point or composition API wrapper appears in the documentation.

How do I use vue2-editor in Nuxt?

Add "vue2-editor/nuxt" to the modules array in nuxt.config.js, and wrap the VueEditor component in Nuxt's client-only component. The README states the client-only wrapper avoids Vue warnings about a content mismatch.

How do I upload images instead of embedding them as Base64?

Set useCustomImageHandler to true and listen for the image-added event, which passes the file, the Editor instance and the cursor position. Post the file to your own endpoint, then call Editor.insertEmbed with the returned URL and resetUploader.

Why do I need to set the id prop when using multiple editors?

The id prop defaults to quill-container, and the README states it is necessary to set it when you have multiple editors in the same view, since two components sharing one DOM id would collide.

Official sources

  1. davidroyer/vue2-editor on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/davidroyer-vue2-editor.svg)](https://hysenlabs.com/projects/davidroyer-vue2-editor)