mrkeyoor.com_
Tue 22 Sept 18:48 UTC
npmWeb Frontendupdated 22 Sept 2026

react-quill review

react-quill 2.0.0 wraps Quill 1.3.7 in a React component for rich-text editing. It accepts HTML strings or Quill Delta documents, wires toolbar and format options through props, reports content and selection changes, and exposes the underlying editor through a ref. Its controlled mode is intentionally hybrid because Quill changes the DOM before React can compare `value`. The current README added a 2025 warning that React users probably do not need this wrapper and points new integrations to Quill's own React example.

Verdict

react-quill 2.0.0 added 16 MB in our install, produced a 107 KB gzipped browser bundle, failed both Node 22 import paths, and carried 2 moderate audit findings. Keep it for tested React 16 through 18 and Quill 1 applications; new work should follow the README's advice and compare direct Quill or a current editor framework.

We installed it

Lab card: what happened when we installed react-quillScreenshot of react-quill documentation
Install✓ · 3s43 packages on disk · 16 MB
ImportESM import fails · require() fails · CommonJS package
Browser107 KBgzipped (375.7 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns20 critical · 0 high · 2 moderate · 0 low (npm audit)

Answers from our run

Does react-quill install cleanly?

Yes. In a fresh container with an empty cache, npm install react-quill finished in 3 seconds, leaving 43 packages and 16 MB on disk. npm audit reported 2 known vulnerabilities.

How much does react-quill add to a browser bundle?

107 KB gzipped (375.7 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does react-quill work with both ESM and CommonJS?

Neither plain import nor require succeeded in our sandbox, so it needs a bundler or extra setup.

Does react-quill include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

react-quill or quill: which should you use?

quill: Use current Quill directly with React when its official integration example covers the required lifecycle. react-quill 2.0.0 added 16 MB in our install, produced a 107 KB gzipped browser bundle, failed both Node 22 import paths, and carried 2 moderate audit findings.

When should you not use react-quill?

You are starting a new React editor. The project's own 2025 README tells readers they probably do not need ReactQuill and links to direct Quill integration.

API stability3/5The version 2 props, callbacks, HTML or Delta values, toolbar modules, and ref methods have remained unchanged since the August 2022 npm release. That consistency helps existing applications, though it freezes the wrapper around Quill 1.3.7 and React peer ranges through 18. The hybrid controlled model is documented, and neither React 19 nor Quill 2 appears in the published compatibility contract.
Docs3/5The README explains themes, HTML and Delta values, the partial-change Delta trap, toolbar modules, custom formats, selection callbacks, read-only mode, refs, and the hybrid controlled behavior. It now opens with a useful 2025 warning directing most new React users to Quill itself. Several CDN references and class-component examples still use old versions, so readers must separate historical samples from the current ecosystem.
Maintenance1/5npm lists 2.0.0 from August 3, 2022 as current. GitHub shows the unarchived repository was last pushed on February 22, 2025, with 7,011 stars and 433 open issues and pull requests. The maintainer's README note sends new users toward direct Quill integration, while the package retains old peer and dependency ranges. That is maintenance mode, not an active compatibility line.
Ecosystem3/5The npm endpoint counted 4,950,911 downloads in the completed week ending August 24, 2026, and existing Quill modules, Delta storage, themes, and toolbar conventions remain useful. Our package check found bundled TypeScript declarations. The integration is stranded on Quill 1 and React 18 or earlier, while active editor development has moved to direct Quill 2, Lexical, Tiptap, and maintained forks.

Use it if

  • An existing React 16, 17, or 18 application already stores Quill 1 Deltas and has tests around ReactQuill's callback behavior.
  • A maintenance patch needs the component ref, prop names, and toolbar setup already used by version 2.0.0.
  • Migration cost is higher than keeping a browser-only editor pinned behind a client boundary.
Skip it if

Setup reality

Our fresh Node 22 Bookworm install of react-quill 2.0.0 finished in 3 seconds. It left 43 packages and 16 MB on disk; the package is 436 KB unpacked, with 3 direct dependencies and 2 peer dependencies. npm audit reported 2 moderate vulnerabilities and no critical, high, or low findings. Inspect the resolved audit paths before shipping because the measured graph is tied to Quill 1 and lodash-era dependencies.

Install matching React and React DOM peers, then load a theme stylesheet such as react-quill/dist/quill.snow.css. Without theme CSS, toolbar controls and tooltips are present but visually incomplete. The package bundles TypeScript declarations and uses CommonJS without an exports map. On Node.js v22.23.2, both require('react-quill') and ESM import failed in our sandbox, so SSR frameworks should load it only in the browser.

The browser cost was 375.7 KB minified and 107 KB gzipped when esbuild imported the whole package. Keep editor code on routes that need it. Version 2.0.0 pulls Quill 1.3.7 and declares React peers through version 18; neither Quill 2 nor React 19 is part of its published support range. The npm release dates to August 2022 even though the README gained a direct-Quill recommendation in 2025.

Pick HTML or Delta as the stored representation and keep that choice consistent. The second onChange argument is only the latest change, so passing it back as value can repeat edits; call editor.getContents() for the complete Delta. Quill-authored HTML still crosses a trust boundary when displayed elsewhere and needs an application sanitization policy. Memoize modules and formats, and use defaultValue when you want Quill to own subsequent editor state.

Patterns

Keep an HTML value in React state controlled-html-editor

import { useState } from 'react'
import ReactQuill from 'react-quill'
import 'react-quill/dist/quill.snow.css'

export function Editor() {
  const [html, setHtml] = useState('')
  return <ReactQuill theme="snow" value={html} onChange={setHtml} />
}

Quill changes its DOM before ReactQuill compares `value`, so version 2.0.0 behaves as a hybrid controlled component.

Let Quill retain editor state uncontrolled-editor

<ReactQuill
  theme="snow"
  defaultValue="<p>Draft text</p>"
  onChange={html => saveDraft(html)}
/>

`defaultValue` initializes the document once. A later change to that prop does not replace the editor contents.

Save the complete Delta store-full-delta

const [document, setDocument] = useState({ ops: [] })

<ReactQuill
  value={document}
  onChange={(_html, _change, _source, editor) => {
    setDocument(editor.getContents())
  }}
/>

The second callback argument contains only the latest operation. Feeding it back as `value` can create a repeated-update loop.

Allow only selected toolbar formats limit-formats

const modules = {
  toolbar: [
    [{ header: [1, 2, false] }],
    ['bold', 'italic', 'underline'],
    [{ list: 'ordered' }, { list: 'bullet' }],
    ['link', 'clean'],
  ],
}
const formats = ['header', 'bold', 'italic', 'underline', 'list', 'bullet', 'link']

<ReactQuill modules={modules} formats={formats} />

A toolbar button does not authorize a format omitted from `formats`; pasted and programmatic content follow the same allowlist.

Focus through the component ref access-quill-instance

import { useRef } from 'react'

const quillRef = useRef(null)
function focusEditor() {
  quillRef.current?.getEditor().focus()
}

<ReactQuill ref={quillRef} defaultValue="" />

`getEditor()` returns Quill's mutable instance. Reserve it for operations that the component props and callback proxy cannot express.

Handle selection and blur read-selection

<ReactQuill
  onChangeSelection={(range, source, editor) => {
    if (range) {
      console.log(range.index, range.length, source)
      console.log(editor.getText(range.index, range.length))
    }
  }}
/>

Version 2.0.0 passes `null` for the range after focus leaves the editor, so check it before reading positions.

Disable editing and hide the toolbar toggle-read-only

<ReactQuill
  theme="snow"
  value={html}
  readOnly={!canEdit}
  modules={{ toolbar: canEdit }}
/>

`readOnly` changes browser interaction only. The save endpoint still needs its own authorization check.

Register a toolbar handler with Quill context add-toolbar-handler

function insertDivider() {
  const range = this.quill.getSelection(true)
  this.quill.insertText(range.index, '\n---\n', 'user')
}

const modules = {
  toolbar: {
    container: [['bold', 'italic'], ['divider']],
    handlers: { divider: insertDivider },
  },
}

Use a normal function when the handler reads `this.quill`; an arrow function does not receive the toolbar module context.

Exclude the editor from Next.js SSR load-without-ssr

import dynamic from 'next/dynamic'

const ReactQuill = dynamic(() => import('react-quill'), { ssr: false })

export function ClientEditor(props) {
  return <ReactQuill theme="snow" {...props} />
}

Both Node 22 import styles failed in our sandbox. A client-only dynamic import avoids evaluating the DOM-dependent package on the server.

Store searchable text beside editor HTML get-plain-text

<ReactQuill
  onChange={(html, _delta, _source, editor) => {
    save({ html, text: editor.getText() })
  }}
/>

Quill plain text usually ends with a newline. Normalize it only when your indexing or character-count rules call for that change.

Alternatives

PackageRegistryPick it when
quillnpmUse current Quill directly with React when its official integration example covers the required lifecycle.
lexicalnpmUse it for a React-oriented editor framework with explicit state and plugin composition.
@tiptap/reactnpmUse it when schema control, extensions, and headless rendering justify a larger editor framework.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.