SimpleNext.js

The comprehensive guide to react-quill (for React and Next.js)

Cover Image for The comprehensive guide to react-quill (for React and Next.js)
Marouane Reda
Marouane Reda
If you need to understand the basics of Next.js, i recommend this course. (Disclaimer : this is an affiliate link that may earn me a small commission, but with no extra cost to you if you choose to enroll)

Quill is an open source, very modular WYSIWYG rich text editor for web apps, that comes with many useful features. React-quill is a Quill component for use with React and React-based frameworks ( like Next.js), that we already had a first look on here. In this article, we will go more in details to explore all the possibilities offered by react-quill to our React and Next.js apps.

Basic usage of react-quill

You can refer to our previous article to see the basic usage of react-quill for Next.js .

For React apps, we need , like Next.js apps , to install the package :

npm install react-quill --save

then use the ReactQuill component :

import React from "react";
 import ReactQuill from 'react-quill';
 import 'react-quill/dist/quill.snow.css';

 function MyComponent() {


   return (
     <ReactQuill theme="snow" ></ReactQuill>
   );
 }

the only difference with Next.js is that we import ReactQuill directly instead of dynamically like this :

import React from "react";
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

function MyComponent() {


  return (
    <ReactQuill theme="snow" />
  );
}

So here he we have the core version of the Quill editor without any features. https://firebasestorage.googleapis.com/v0/b/kmx1-16598.appspot.com/o/blog%2FCC8FF154-F1D4-4C92-B56C-73D32DDAE076_1_201_a.jpeg?alt=media&token=f3f57795-337a-40fd-8c38-b50cfd485719 From now on in the article we will use Next.js instead of vanilla React, but all of what will be explained is applicable to Vanilla React also.

Modules

Quill’s behavior and functionality can be customized via Modules. This modules include the ToolBar module, Keyboard, History, ClipBoard and Syntax.

To enable a module, simply include it in Quill’s configuration. In our previous article, we configured the ToolBar module and clipboard module:

const modules = {
      toolbar: [
        [{ header: '1' }, { header: '2' }, { font: [] }],
        [{ size: [] }],
        ['bold', 'italic', 'underline', 'strike', 'blockquote'],
        [
          { list: 'ordered' },
          { list: 'bullet' },
          { indent: '-1' },
          { indent: '+1' },
        ],
        ['link', 'image', 'video'],
        ['clean'],
      ],
      clipboard: {
        // toggle to add extra line breaks when pasting HTML:
        matchVisual: false,
      },
    }

then :

export default function Home() {
      return <QuillNoSSRWrapper modules={modules} formats={formats} theme="snow" />
    }

the result is :

https://firebasestorage.googleapis.com/v0/b/kmx1-16598.appspot.com/o/blog%2F4B2BD43A-D478-4201-BE9D-1E4F83BD7DBC_1_201_a.jpeg?alt=media&token=71055881-52c9-47e1-970d-96a73a2f4149

ToolBar, Keyboard and history are required and do not need to be explicitly added , but they are still fully configurable.

ToolBar Module

the toolbar allows the user to edit the text. If we go back to our example, we added these formats to our toolbar : ```javascript
 toolbar: [
  [{ header: &#39;1&#39; }, { header: &#39;2&#39; }, { font: [] }],
    [{ size: [] }],
    [&#39;bold&#39;, &#39;italic&#39;, &#39;underline&#39;, &#39;strike&#39;, &#39;blockquote&#39;],
    [
      { list: &#39;ordered&#39; },
      { list: &#39;bullet&#39; },
      { indent: &#39;-1&#39; },
      { indent: &#39;+1&#39; },
    ],
    [&#39;link&#39;, &#39;image&#39;, &#39;video&#39;],
    [&#39;clean&#39;],
]

each element of the array toolbar is a group of controls, that will be shown separately in the toolbar :

Buttons with custom values can be specified with an Object with the name of the format as its only key.
`{ header: &#39;1&#39; }, { header: &#39;2&#39; }`
Dropdowns are similarly specified by an Object, but with an array of possible values; if empty the values are default values

`{ size: [] }`

here is a more detailed look of options for toolbar :

    [&#39;bold&#39;, &#39;italic&#39;, &#39;underline&#39;, &#39;strike&#39;],        // toggled buttons
      [&#39;blockquote&#39;, &#39;code-block&#39;],
    
      [{ &#39;header&#39;: 1 }, { &#39;header&#39;: 2 }],               // custom button values
      [{ &#39;list&#39;: &#39;ordered&#39;}, { &#39;list&#39;: &#39;bullet&#39; }],
      [{ &#39;script&#39;: &#39;sub&#39;}, { &#39;script&#39;: &#39;super&#39; }],      // superscript/subscript
      [{ &#39;indent&#39;: &#39;-1&#39;}, { &#39;indent&#39;: &#39;+1&#39; }],          // outdent/indent
      [{ &#39;direction&#39;: &#39;rtl&#39; }],                         // text direction
    
      [{ &#39;size&#39;: [&#39;small&#39;, false, &#39;large&#39;, &#39;huge&#39;] }],  // custom dropdown
      [{ &#39;header&#39;: [1, 2, 3, 4, 5, 6, false] }],
    
      [{ &#39;color&#39;: [] }, { &#39;background&#39;: [] }],          // dropdown with defaults from theme
      [{ &#39;font&#39;: [] }],
      [{ &#39;align&#39;: [] }],
    
      [&#39;clean&#39;]                                         // remove formatting button
    
### Keyboard Module
The Keyboard module enables custom behavior for keyboard events in particular contexts. Quill uses this to bind formatting hotkeys and prevent undesirable browser side effects.
Refer here for more in depth information.

### History Module
The History module is responsible for handling undo and redo for Quill. It can be configured with the following options:

- delay

Default: 1000
Changes occuring within the delay number of milliseconds is merged into a single change.
For example, with delay set to 0, nearly every character is recorded as one change and so undo would undo one character at a time. With delay set to 1000, undo would undo all changes that occured within the last 1000 milliseconds.
- maxStack

Default: 100
Maximum size of the history’s undo/redo stack. Merged changes with the delay option counts as a singular change.
- userOnly

Default: false
By default all changes, whether originating from user input or programmatically through the API, are treated the same and change be undone or redone by the history module. If userOnly is set to true, only user changes will be undone or redone.


## Formats
Quill supports a number of formats, both in UI controls and API calls.
By default all formats are enabled and allowed to exist within a Quill editor and can be configured with the formats option. This is separate from adding a control in the Toolbar. For example, you can configure Quill to allow bolded content to be pasted into an editor that has no bold button in the toolbar.


**Inline**
* Background Color - background
* Bold - bold
* Color - color
* Font - font
* Inline Code - code
* Italic - italic
* Link - link
* Size - size
* Strikethrough - strike
* Superscript/Subscript - script
* Underline - underline

**Block**
* Blockquote - blockquote
* Header - header
* Indent - indent
* List - list
* Text Alignment - align
* Text Direction - direction
* Code Block - code-block

**Embeds**
* Formula - formula (requires KaTex)
* Image - image
* Video - video

## Quill usage props : value, onChange, placeholder

After seeing how we can customize our Quill editor, we will now see how we can use it in real life using three main props: value, onChange, placeholder.

Let’s return to our example and update it with these props :

```javascript
    import dynamic from &#39;next/dynamic&#39;
    import React, { useState } from &quot;react&quot;;
    import parse from &#39;html-react-parser&#39;;

    const QuillNoSSRWrapper = dynamic(import(&#39;react-quill&#39;), {
      ssr: false,
      loading: () =&gt; &lt;p&gt;Loading ...&lt;/p&gt;,
    })


    const modules = {
      toolbar: [
        [{ header: &#39;1&#39; }, { header: &#39;2&#39; }, { font: [] }],
        [{ size: [] }],
        [&#39;bold&#39;, &#39;italic&#39;, &#39;underline&#39;, &#39;strike&#39;, &#39;blockquote&#39;],
        [
          { list: &#39;ordered&#39; },
          { list: &#39;bullet&#39; },
          { indent: &#39;-1&#39; },
          { indent: &#39;+1&#39; },
        ],
        [&#39;link&#39;, &#39;image&#39;, &#39;video&#39;],
        [&#39;clean&#39;],
      ],
      clipboard: {
        // toggle to add extra line breaks when pasting HTML:
        matchVisual: false,
      },
    }
    /*
     * Quill editor formats
     * See https://quilljs.com/docs/formats/
     */
    const formats = [
      &#39;header&#39;,
      &#39;font&#39;,
      &#39;size&#39;,
      &#39;bold&#39;,
      &#39;italic&#39;,
      &#39;underline&#39;,
      &#39;strike&#39;,
      &#39;blockquote&#39;,
      &#39;list&#39;,
      &#39;bullet&#39;,
      &#39;indent&#39;,
      &#39;link&#39;,
      &#39;image&#39;,
      &#39;video&#39;,
    ]

    export default function Home() {
      const [value, setValue] = useState(&#39;&#39;);
      return (
        &lt;div&gt;
      &lt;QuillNoSSRWrapper modules={modules} placeholder=&#39;compose here&#39; value={value} onChange={setValue} formats={formats} theme=&quot;snow&quot;  /&gt;

      &lt;p&gt;{value}&lt;/p&gt;
      {parse(value)}
      &lt;/div&gt;
      )}

placeholder

the placeholder is just what appears by default in our Quill component before we type anything in it , in our example the placeholder is ‘compose here ‘ , so the result is : https://firebasestorage.googleapis.com/v0/b/kmx1-16598.appspot.com/o/blog%2FCapture%20d%E2%80%99e%CC%81cran%202021-08-11%20a%CC%80%2021.10.22.png?alt=media&token=11dd5560-fd3b-4e6e-9dbe-7fc812da84a2

onChange

the onChange event executes a javascript whenever a change is occurring in our Quill component. In our case, onChange={setValue} , which means we will set the value property in our state with the current value in our editor

Final result

To show the result of our code, we selected the text to be H2, italic and underlined. You will see them toggled in blue in the toolbar :

https://firebasestorage.googleapis.com/v0/b/kmx1-16598.appspot.com/o/blog%2FCapture%20d%E2%80%99e%CC%81cran%202021-08-11%20a%CC%80%2021.21.27.png?alt=media&token=5a19cc14-ae31-4ca8-8880-2ca5d6b0d6c3

the <p>{value}</p> returns the content of value which is the html code as shown in the image : <h2><em><u>this is a test</u></em></h2>.

to show the actual rendering, we use ‘html-react-parser’ to parse the html code.