logo
Basic Utils
Home

React Quill Tutorial

quilljs.com image
quilljs.com image
quilljs.com image

Introduction to React Quill

What is React Quill?

React Quill is a lightweight and flexible wrapper for the Quill.js editor that is particularly customized for React applications. It's based on Quil.js, a powerful, open-source WYSIWYG(what you see is what you get)WYSIWYG editor known for modularity and extensibility. Quill.js was developed and is maintained by slab company. Quill has had significant updates since its first release, including a major 2.0 version in April 2024 that improved performance and updated the core. The GitHub repository has risen from 23,000 stars at the most recent version of Quill 1.3.7 to over 38,000 stars with the official release of Quill 2.0, showing its rising popularity and usage as seen in Announcing Quill 2.0. React Quill combines Quill.js with React for advanced rich text editing in a React style (React Quill GitHub Repository, 2025). It has been recognized for its quality and user satisfaction, achieving a user review of 4.1 out of 5 stars on G2 and a 4.5 out of 5 stars rating on Capterra.

React Quill characteristics:

  • Declarative Syntax: This fits in with React's component-based architecture.
  • Customization: It's modular allowing for high customization.
  • Formats: Content can be maintained in Quill Delta format or exported to HTML.

Why Use React Quill?

Other rich text editors, such as TinyMCE and CKEditor, exist. However, Quilljs stands out from them for the following reasons:

  1. Developed for React applications: React Quill utilizes React's state management and re-render functionalities without complexity.
  2. Lightweight and Modular: Quill.js, the heart of React Quill, is highly modular, allowing developers to integrate just the functionality they want (Quill.js Documentation, 2025).
  3. Extensibility: React Quill is flexible and enables plugins and custom modules, making it an ideal solution for applications that require complex functionality like as tables, image uploads, and custom widgets.

ℹ️

Did You Know?

React Quill uses Quill.js’s Delta format to represent content. This allows for easy JSON manipulation and compatibility with various storage systems.

Applications of React Quill

React Quill is highly versatile and can be used in various contexts, including:

  • Content Management Systems (CMS): Used for easy formatting of text-rich articles and blog entries.
  • Email Editors: Users may create and format emails using rich text and embedded media.
  • Collaborative Tools: Enables real-time collaborative editing in apps such as document editors and chat platforms.
  • Educational Platforms: Enables the production and maintenance of prepared notes, assignments, and quizzes.

In conclusion, React Quill offers a balance between performance and functionality. While some developers have reported challenges with Quill's documentation and integration, as seen in this StackOverflow thread, it remains an ideal candidate for any developer or content creator looking to add rich text editing capability to their platform. React Quill's ability to handle rich text in an intuitive manner makes it a go-to solution for applications with user-generated content, (Dhiwise Blog, 2025). In the next sections, we will dive deeper into Quill and its integration.

React Quill vs Slate vs TinyMCE vs CKEditor vs Draft.js

While React Quill is a powerful choice, it faces stiff competition from its well-established competitors. Let’s compare React Quill with its competitors — Slate, TinyMCE, CKEditor, and Draft.js — based on key factors such as features, ease of use, and customization.

Quilljs

Strengths

  • Lightweight and modular
  • Extensibility through custom modules and blots
  • Seamless integration with React
  • Free and opensource

Weaknesses

The documentation is lacking and has a steep learning curve.

Best for

Developers looking for a customizable, lightweight solution for React apps.

TinyMCE

Strengths

  • User friendly
  • Offers a managed solution that is cloud-based
  • Feature-rich i.e image upload, tables, advanced formatting

Weaknesses

  • It's not entirely free. It has paid premium features.
  • The customization options are not as extensive as the other editors.

Best for

Teams that need a feature-rich, managed solution with professional support.

CKEditor

Strengths

  • supports real-time collaborative editing
  • It has extensive plugin support
  • Cross-platform: It supports multiple frameworks.

Weaknesses

  • It requires licensing and, therefore not entirely free
  • it's complex and large.

Best For

  • Projects that require collaborative editing and are willing to handle the complexity and licensing fees.

Draft.js

Strengths

  • Highly customizable
  • Designed for React and integrating well with React state management.

Challenges

  • Complexity in the initial setup
  • Steep learning curve for beginners.

Best for

React apps that need complex functionality and have the development resources to handle the setup.

Slate

Strengths

  • Extremely customizable
  • gives developers access to low-level APIS

Weaknesses

  • Steep learning curve
  • Complex setup.

Best for

  • Projects that need a highly tailored solution and that can accommodate the steep learning curve.

There isn't a one-size-fits-all solution. The optimal solution balances between learning curve, development time, and customizability. For a more detailed comparison, you can refer to this resource: NPM Compare

Setting Up React Quill Example

In this section, we will set up a React Quill example and demonstrate how to integrate React Quill with Next.js.

Installing React Quill in a React Project

Follow the below steps to install React Quill and its dependencies.

  1. Install React Quill

Add React Quill using npm or yarn:


npm install react-quill
# or
yarn add react-quill

Install Quill.js (Optional)

React Quill installation includesQuill.js, but you may install it separately if you want to tweak Quill modules heavily.


npm install quill

Install Types for TypeScript

To enable type-checking in TypeScript, install the type definitions:


npm install --save-dev @types/react-quill

Set Up React Quills CSS Styles

Import Quill’s CSS to ensure proper styling:


import 'react-quill/dist/quill.snow.css';

Handling Server-Side Rendering (SSR) in Next.js

If you are using Next.js it's worth noting that React Quill depends on the DOM. This means it may cause errors during server-side rendering in frameworks such as Next.js. To resolve this, use dynamic imports:

  1. Install Next.js if not already installed:

The following code shows how to install Next.js


npx create-next-app@latest my-next-app --typescript

React Quill Dynamic Imports in Next.js

When using React Quill in Next.js, ensure you use dynamic imports to avoid "window is not defined" errors during server-side rendering.

React Quill Dynamic Import for Next.js:

Use Next.js’s dynamic function to load React Quill only on the client side. Quill is a client-side tool and should only be loaded in the browser environment:


import dynamic from 'next/dynamic';
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
export default function Editor() {
  return <ReactQuill theme="snow" />;
}

The above code ensures React Quill is only rendered in the browser, preventing SSR-related errors (2025-01-01). (Next.js Documentation, 2025)..

React Quill Example in Next.js

Below is code for a functional component showcasing a basic React Quill editor in Next.js:


import dynamic from 'next/dynamic';
import 'react-quill/dist/quill.snow.css';
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
export default function Editor() {
  const [content, setContent] = React.useState<string>('');
  return (
    <div>
      <h2>Rich Text Editor</h2>
      <ReactQuill
        theme="snow"
        value={content}
        onChange={setContent}
        placeholder="Write something amazing..."
      />
    </div>
  );
}

The code above shows how to integrate React Quill in Next.js by dynamically loading the editor on the client side. The snow theme is used and the state is managed via useState hook.

Setting Up React Quill Themes

React Quill supports two themes:

Snow Theme: A clean, flat toolbar for traditional interfaces.

Bubble Theme: A floating tooltip for formatting options near the selected text.

This setup lays the groundwork for adding advanced customizations, such as toolbar adjustments, in the next section.

Customizing React Quill Toolbar

Overview of Quill’s Toolbar Options

React Quill, being a wrapper for Quill.js, comes with a customizable toolbar for text formatting, links, and images. The default setup provides a basic toolbar:

  • Default Toolbar:

Code illustrating setting up quill with the default toolbar.


<ReactQuill theme="snow" />

  • Custom Toolbar:

To get more functionality, use the modules prop to define custom control groups.

Below is the code for the React Quill toolbar customization


const modules = {
  toolbar: [
    [{ header: [1, 2, false] }],
    ['bold', 'italic', 'underline'],
    ['link', 'image']
  ]
};
<ReactQuill theme="snow" modules={modules} />;

This configuration enables headers (levels 1, 2, or none), text formatting (bold, italic, underline), and link/image insertion.

Adding Custom Buttons to Toolbar in React Quill

You can also extend the toolbar by adding custom buttons.

Steps to Add Custom Buttons To React Quill:

  1. Define a Custom Handler:

Write a custom handler function to specify the behavior of the button.

Example: Custom handler for inserting a timestamp:


const insertTimestamp = () => {
  const quill = this.quill; // Access the Quill instance
  const cursorPosition = quill.getSelection()?.index || 0;
  quill.insertText(cursorPosition, new Date().toLocaleString());
};

Register the Button:

Register your handler with the toolbar module with the following.


const modules = {
  toolbar: {
    container: [
      ['bold', 'italic'],
      ['timestamp']
    ],
    handlers: {
      timestamp: insertTimestamp
    }
  }
};
<ReactQuill theme="snow" modules={modules} />;

Styling the React Quill Toolbar with CSS

The toolbar also allows you to customize its looks using CSS.

Example toolbar customizations:

  1. Customizing Toolbar Buttons:

Below code styles specific buttons such as bold


.ql-toolbar .ql-bold {
  color: #3498db;
  font-weight: bold;
}

Styling the Toolbar Container:

The below code shows how you can also adjust the toolbar's overall look.


.ql-toolbar {
  background-color: #f5f5f5;
  border-radius: 8px;
}

Responsive Toolbar:

Use media queries to adjust the toolbar layout for smaller screens as seen in below code.


@media (max-width: 600px) {
  .ql-toolbar {
    flex-wrap: wrap;
  }
}

Advanced Features: React Quil Table, React Quill Image Upload

React Quill Image Upload

React Quill does not inherently handle picture uploads, however, you can rely on services Cloudinary or Firebase.

  1. Customizing the Toolbar for Image Button

To enable image uploads you define a custom image handler and attach it to the toolbar. The following code shows the React Quill image upload example


const modules = {
  toolbar: {
    container: [
      ['bold', 'italic', 'underline'],
      ['image']
    ],
    handlers: {
      image: () => handleImageUpload()
    }
  }
};

code breakdown:

  • container: used to specify and describe the toolbar buttons for formatting.
  • Handlers are used to define the custom behavior of the toolbar buttons. In our example above, the image button triggers the handleImageUpload().

Implementing the Image Upload Handler

Use a service like Cloudinary to upload photos and enter the generated URL into the editor:


const handleImageUpload = () => {
  const input = document.createElement('input');
  input.setAttribute('type', 'file');
  input.setAttribute('accept', 'image/*');
  input.click();
  input.onchange = async () => {
    const file = input.files?.[0];
    if (file) {
      const formData = new FormData();
      formData.append('file', file);
      formData.append('upload_preset', 'your_preset'); // Cloudinary preset
      const response = await fetch('https://api.cloudinary.com/v1_1/your_cloud_name/image/upload', {
        method: 'POST',
        body: formData
      });
      const data = await response.json();
      const quill = this.quill; // Access the Quill instance
      const range = quill.getSelection();
      quill.insertEmbed(range?.index || 0, 'image', data.secure_url);
    }
  };
};

code breakdown:

  1. File Validation: Ensures that a valid file is available before proceeding.
  2. Image Upload: Upload the extracted image to Cloudinary with your account details.
  3. Embed the image: After upload, insert the image at the current cursor position using a quill.insertEmbed.

React Quill with Table

Quill.js does not support tables by default. However, you may increase its capability by adding plugins such as soccer Loway (2025-01-01). Quill Better Table.:

  1. Install the Plugin:

Use the code below to install quill-better-table.


npm install quill-better-table
  1. Register the plugin with quill:

Import and register the plugin:


import Quill from 'quill';
import QuillBetterTable from 'quill-better-table';
Quill.register('modules/better-table', QuillBetterTable);
  1. Configure the Toolbar:

Add table options to the toolbar and customize table operations:


const modules = {
  toolbar: [['bold', 'italic'], ['better-table']], // Include table support in the toolbar
  'better-table': {
    operationMenu: {
      items: ['mergeCells', 'unmergeCells'], // Enable merging and unmerging of table cells
    },
  },
};

  1. Use the Configured Editor:

<ReactQuill theme="snow" modules={modules} />;

code breakdown

We first register the plugin with Quill.

We configure the toolbar to include an option for adding tables.

We use the operationMenu to define options for managing table cells.

Custom React Quill Themes

To give your editor a unique look, you can override Quill's default CSS to your liking.

customizing Quills CSS


.ql-editor {
  background-color: #f8f8f8;
  color: #333;
  font-family: 'Arial', sans-serif;
  font-size: 16px;
}
.ql-toolbar {
  background-color: #004085;
  color: #fff;
  border-radius: 5px;
}
.ql-toolbar .ql-active {
  color: #ffd700;
}

Apply the Theme

Import your custom:


import 'react-quill/dist/quill.snow.css';
import './custom-quill-theme.css';

Use the theme


<ReactQuill theme="snow" />;

This approach allows you to override Quill's default CSS while retaining its behavior.

Managing Editor Content in React Quill

React Quill Delta Format

Quill.js uses the Delta format to store every single operation that has occurred in the editor. It's efficient for structured content storage and collaborative editing.

Example Code showing Quill Delta Output:


{
  "ops": [
    { "insert": "Hello " },
    { "insert": "world", "attributes": { "bold": true } },
    { "insert": "!" }
  ]
}
  • Advantages:
    • Compact and simple to use for group editing.
    • Formatting information is retained even after storage.

Use Case: Suitable for complex applications such as collaborative editing. Quill.js (2025-01-01). (Quill.js Delta Documentation, 2025)..

Warning on xss attacks with raw HTML!

Avoid saving raw HTML to your database. Always sanitize content to prevent security vulnerabilities like XSS attacks.

HTML Format In React Quill

React Quill may also create and accept HTML strings containing the editor's content.

Example HTML Output:


<p>Hello <strong>world</strong>!</p>

    • Advantages:
      • Simple to render immediately in a browser.
    • Use Case: Ideal for showing material in web applications without requiring further processing.
  1. Switching Between Formats:

You can switch between delta and HTML formats using the value prop.

Saving Content to a Database

The choice of format when saving to storage depends on your use case and storage efficiency.

Saving Quill Delta Format

Example


const content = JSON.stringify(editorContent); // editorContent is the Delta output
  • Advantages:
    • Easier to edit, update, or merge content later.
    • Works seamlessly with Quill's Delta-based APIs.

Saving HTML Format

  • Save the content as a string in the database.

Example:


const content = editorContent; // editorContent is the HTML string
    • Advantages:
      • ease of use for online applications.

Security Tip: Use libraries like Cure53 (2024-12-09). DOMPurify. to ensure appropriate sanitization and avoid XSS attacks.

Database Design Tips

  • Use TEXT or LONGTEXT for storing rich text content in databases like MySQL.
  • For Delta data, consider compressing large content for storage efficiency.

Converting HTML to Plain Text

Some scenarios such as previews or summaries, convert rich text to plain text. Here are some of the methods you can use.

Convert HTML to Plain Text

Strip HTML tags using a DOM parser.

Example code:


const htmlToPlainText = (html: string): string => {
  const tempElement = document.createElement('div');
  tempElement.innerHTML = html;
  return tempElement.textContent || '';
};

Alternatively, leverage libraries like (2023-03-23). html-to-text. for advanced conversions.

Example code with HTML-to-text:


import { convert } from 'html-to-text';
const plainText = convert(htmlContent, {
  wordwrap: 130 // Optional: Wrap text for better readability
});

Delta to Plain Text:

Extract plain text directly from Delta format by iterating over its operations.

Example:


const deltaToPlainText = (delta: any): string => {
  return delta.ops.map((op: any) => op.insert || '').join('');
};

Common Challenges and Debugging Tips In React Quill

SSR Issues in Next.js

React Quill relies on the window object, which is unavailable during server-side rendering (SSR) in Next.js. This can trigger the following error:

Error Example:


ReferenceError: window is not defined

Solution: Dynamic Import

Use Next.js' dynamic() to ensure quill.js is loaded only on the client side.

Example code of dynamic imports with react quill:


import dynamic from 'next/dynamic';
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
const Editor = () => {
  return <ReactQuill theme="snow" />;
};
export default Editor;

  1. Additional Compatibility Tips:
    • Wrap quil-related plugins and themes in client-side checks to ensure they aren't loaded on the server side.
    • Utilize the useEffect hook for delayed setup when working with large data to avoid performance bottlenecks, Vercel (2025-01-01). (Next.js Documentation, 2025)..

Handling Large Content

Working with large amounts of content can lead to performance bottlenecks. Here are tips on how to do it.

  1. Lazy Loading Content:

Load content dynamically to optimise rendering.


const [content, setContent] = useState<string | null>(null);
useEffect(() => {
  fetchContent(); // Simulate fetching content from an API
}, []);
const fetchContent = async () => {
  const data = await fetch('/api/content');
  const result = await data.json();
  setContent(result.html); // or Delta format
};
<ReactQuill theme="snow" value={content || ''} />;

  1. Optimizing Rendering:
  2. Database Optimization:
    • Store Delta format instead of HTML to minimize storage size.
    • Use pagination for loading sections of content dynamically.

Dealing with Unsupported Features

Although extensible, Quill doesn't support advanced features out-of-the-box.

Creating Custom Widgets:

Create custom blots to extend editor functionality.


const BlockEmbed = Quill.import('blots/block/embed');
class CustomWidget extends BlockEmbed {
  static create(value: any) {
    const node = super.create();
    node.setAttribute('data-id', value.id);
    node.innerHTML = `<div>Your Custom Widget</div>`;
    return node;
  }
}
CustomWidget.blotName = 'widget';
CustomWidget.tagName = 'div';
Quill.register(CustomWidget);

Testing and Debugging Extensions:

Conclusion

React Quill is a powerful wrapper around the extensible Quill.js. It stands out by its rich editing capabilities and modularity making it ideal for a wide range of applications. Here are the main key takeaways:

Key Takeaways

  1. Ease of Use: React Quill provides an intuitive API that seamlessly integrates with React.
  2. Customization: It is highly customizable allowing the user the extend it via blots and custom modules
  3. Advanced Features: With a little coding, Quill can easily provide very advanced features to suit your needs.

For developers seeking to integrate the WYSIWYG editor into a site, React Quill is a standout option.

Happy coding and seamless editing!

Frequently Asked Questions

React Quill is a React wrapper for the Quill.js rich text editor, allowing seamless integration with React applications.

React Quill uses Quill.js's Delta format, a JSON-based structure, to represent and manipulate content.

Yes, but you need to address server-side rendering issues by dynamically importing React Quill.

Yes, you can customize the toolbar by providing a toolbar configuration or adding custom buttons.

You can handle image uploads by using handlers for the toolbar and integrating services like Cloudinary or Firebase.

It’s best to save content in Quill.js's Delta format or sanitized HTML, depending on your use case.

Tables are not supported natively but can be added using plugins or custom extensions.

Yes, React Quill can handle large-scale applications by optimizing content rendering and using lazy loading.

Yes, React Quill provides TypeScript support, and you can define types for its props and configurations.

You can resolve this issue by using Next.js's dynamic import to load React Quill client-side only.

References

Inline References

  1. Amaro, Z. (August 4, 2017). React Quill Documentation. *GitHub*. Retrieved August 4, 2017 from https://github.com/zenoamaro/react-quill
  2. (November 30, 2024). Why Quill?. *Quill.js*. Retrieved November 30, 2024 from https://quilljs.com/docs/why-quill
  3. (January 1, 2025). Best Rich Text Editors for React. *LogRocket*. Retrieved January 1, 2025 from https://blog.logrocket.com/best-rich-text-editors-react
  4. (January 1, 2025). The Impact of React Quill in Web Development: A Deep Dive. *Dhiwise*. Retrieved January 1, 2025 from https://www.dhiwise.com/post/the-impact-of-react-quill-in-web-development-a-deep-dive
  5. (January 1, 2025). Dynamic Import. *Next.js*. Retrieved January 1, 2025 from ttps://nextjs.org/docs/advanced-features/dynamic-import
  6. Loway, S. (January 1, 2025). Quill Better Table Plugin. *GitHub*. Retrieved January 1, 2025 from https://github.com/soccerloway/quill-better-table
  7. (March 23, 2023). Html-to-text Library. *NPMJS*. Retrieved March 23, 2023 from https://www.npmjs.com/package/html-to-text
  8. (December 9, 2024). DOMPurify Library Documentation. *Github*. Retrieved December 9, 2024 from https://github.com/cure53/DOMPurify
  9. (January 1, 2025). Delta Format Documentation. *Quill.js Documentation*. Retrieved January 1, 2025 from https://quilljs.com/docs/delta/
  10. (April 9, 2023). React Virtualized Library. *GitHub*. Retrieved April 9, 2023 from https://github.com/bvaughn/react-virtualized
  11. (January 1, 2025). Dynamic Imports in Next.js. *Next.js*. Retrieved January 1, 2025 from https://nextjs.org/docs/dynamic-import
  12. (January 1, 2025). GitHub Issues Tracker. *GitHub*. Retrieved January 1, 2025 from https://github.com/quilljs/quill/issues
  13. (February 28, 2025). WYSIWYG. *Wikipedia*. Retrieved February 28, 2025 from https://en.wikipedia.org/wiki/WYSIWYG#:~:text=In%20computing%2C%20WYSIWYG%20(%2F%CB%88,web%20page%2C%20or%20slide%20presentation.
  14. Li, Z. (April 16, 2024). Announcing Quill 2.0. *Slab*. Retrieved April 16, 2024 from https://slab.com/blog/announcing-quill-2-0/

Background References

  1. (December 28, 2024). Text Editor. *Wikipedia*. Retrieved December 28, 2024 from https://en.wikipedia.org/wiki/Text_editor
  2. (December 18, 2024). Cross Site Scripting Prevention Cheat Sheet. *https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html*. Retrieved December 18, 2024 from https://owasp.org/xss-prevention-cheat-sheet
  3. (December 24, 2024). WYSIWYG. *Wikipedia*. Retrieved December 24, 2024 from https://en.wikipedia.org/wiki/WYSIWYG
  4. (January 3, 2025). Comparison with Other Rich Text Editors. *Quilljs*. Retrieved January 3, 2025 from https://v1.quilljs.com/guides/comparison-with-other-rich-text-editors
  5. Elemuwa, F. (November 2, 2023). Best text editors for React. *LogRocket*. Retrieved November 2, 2023 from https://blog.logrocket.com/best-text-editors-react

About the Author

Joseph Horace's photo

Joseph Horace

Horace is a dedicated software developer with a deep passion for technology and problem-solving. With years of experience in developing robust and scalable applications, Horace specializes in building user-friendly solutions using cutting-edge technologies. His expertise spans across multiple areas of software development, with a focus on delivering high-quality code and seamless user experiences. Horace believes in continuous learning and enjoys sharing insights with the community through contributions and collaborations. When not coding, he enjoys exploring new technologies and staying updated on industry trends.

Comments

logo
Basic Utils

simplify and inspire technology

©2024, basicutils.com