Search code examples
reactjsnext.jsquillreact-quillreact-quilljs

ReactQuill no longer working, forces focus off of element/textarea due to DOMNodeInserted call


I have been using the react-quill package in my NextJS 14 application. It has been working properly until today, I went to write a new post and my focus in the textarea would jump back to the top of the page somewhere off of the <ReactQuill/> component. The following deprecation warning is logged at the time of the issue occurrence:

[Deprecation] Listener added for a 'DOMNodeInserted' mutation event. Support for this event type has been removed, and this event will no longer be fired. See https://chromestatus.com/feature/5083947249172480 for more information.

After visiting the page it seems that in its current usage, the ReactQuill component is calling for the DOMNodeInserted event and the Chrome web browser is now blocking this action. I'm not sure how to get ReactQuill to stop performing this action.

My current implementation of ReactQuill:

"use client"

import React, { useState } from 'react';
import dynamic from 'next/dynamic';
import 'react-quill/dist/quill.snow.css';
import axios from 'axios';

const NewPostPage = () => {

    const [content, setContent] = useState<string>('');
    const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });

    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);

    const title = formData.get('title') as string;
    const author = formData.get('author') as string;

   try {
        const response = await axios.post('/api/posts/create', {
        title,
        author,
        content,
    });

        if (response.status === 200) {
            alert('Post created successfully!');
            window.location.href = '/';
        }
    } catch (error: any) {
        throw new Error('Error creating post:', error);
    }
};

return (
<>
    <div className="p-4">
        <h1 className="text-3xl font-bold mb-2">Creating New Blog Post</h1>
        <hr className="mb-6"/>
    </div>
    <form onSubmit={handleSubmit}>
        <div className="p-4">
        <label htmlFor="author" className="text-gray-200 font-bold pb-4">Blog Post Title</label>
        <br/><br/>
        <input type="text" name="title" id="title" placeholder="Blog Post Title" className="w-full mb-4 p-3 bg-black" autoFocus={true} required />
    </div>
    <div className="p-4">
        <label htmlFor="author" className="text-gray-200 font-bold pb-4">Author Name</label>
        <br/><br/>
        <input type="text" name="author" id="author" placeholder="Author Name" className="w-full mb-4 p-3 bg-black" required />
    </div>
    <div className="p-4">
        <label htmlFor="content" className="text-gray-200 font-bold">Blog Content</label>
        <br/><br/>
        <ReactQuill
          theme="snow"
          value={content}
          onChange={setContent}
          style={{ height: '33vh', marginBottom: '40px', color: 'white' }}
        />
    </div>
    <div className="p-4">
      <button type="submit" className="border border-white px-4 py-2 rounded-md hover:bg-slate-900">Create Post</button>
    </div>
  </form>
        </>
    );
};

export default NewPostPage;

The version of react-quill used here is 2.0.0


Solution

  • You can handle the DOMNodeInserted call with caching when you couple the React useMemo method along with the ReactQuill setup in the initialization as it caches the value of the component between re-renders.

    The new implementation of ReactQuill in this instance would be to import useMemo and then wrap the initialization to the ReactQuill constant:

    import React, { useState, useMemo } from 'react'
    ...
    const ReactQuill = useMemo(() => dynamic(() => import('react-quill'), { ssr: false }), []);
    ...
    return (
    ...
    <ReactQuill
      theme="snow"
      value={content}
      onChange={setContent}
      style={{ height: '33vh', marginBottom: '40px', color: 'white' }} />
    ...
    )