9

I'm getting an error message like this

error - ReferenceError: document is not defined

Why is this? I've never had an error like this so I'm really confused. Please help for the seniors there.

My code =

import { useState } from "react";
import dynamic from 'next/dynamic';
import { Quill } from "react-quill";
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
import toolbarOptions from "./toolbar";

import 'react-quill/dist/quill.bubble.css';
const BubbleTheme = Quill.import("themes/bubble");

class ExtendBubbleTheme extends BubbleTheme {
  constructor(quill, options) {
    super(quill, options);

    quill.on("selection-change", (range) => {
      if (range) {
        quill.theme.tooltip.show();
        quill.theme.tooltip.position(quill.getBounds(range));
      }
    });
  }
}

Quill.register("themes/bubble", ExtendBubbleTheme);

import styles from '../styles/Home.module.css'

export default function Home() {
  return (
    <div className={styles.container}>
      <h1>Quill Editor</h1>
        <ReactQuill
          theme="bubble"
          placeholder="Compose an epic..."
          modules={{ toolbar: toolbarOptions }}
        />
    </div>
  )
}
1
  • 3
    try to import dynamically the whole component not only react-quill Commented Jul 20, 2022 at 7:45

6 Answers 6

43

Ran into this same issue. Using a Next Dynamic Import with this functional component implementation works like a charm:

import { useState, useMemo } from "react";
import dynamic from "next/dynamic";

const YourComponent = () => {
  const [value, setValue] = useState("");
  const ReactQuill = useMemo(() => dynamic(() => import('react-quill'), { ssr: false }),[]);

  return (
    <div>
      {/*... */}
      <ReactQuill theme="snow" value={value} onChange={setValue} />
    </div>
  );
};


export default YourComponent;
Sign up to request clarification or add additional context in comments.

8 Comments

this worked with Next 13 too
@MohammedBekele Yes it does bud! 🫡
It's so good solution
Hey there, I run into this and this solution works whilst developing and in Next 12, however I now updated to Next 13 and it throws an error during the build ReferenceError: document is not defined Any idea? @MohammedBekele did you have to do something special to make it build in Next 13?
@MatteoCarpi have you tried to use "use client"?
|
4

[Solved] Working solution...

Create Own Component file MyEditor.js and paste below code

import dynamic from 'next/dynamic';
import { useRef } from 'react';
import { useEffect, useState } from 'react';

const QuillNoSSRWrapper = dynamic(
  async () => {
    const { default: RQ } = await import('react-quill');
    return ({ ...props }) => <RQ {...props} />;
  },
  {
    ssr: false,
  }
);

const modules = {
  toolbar: [
    [{ header: '1' }, { header: '2' }, { header: '3' }, { 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,
  },
}


export default function MyEditor(props) {
  const qRef = useRef(null);


  const [content, setContent] = useState(props.value || '');
  
  useEffect(() => {
    props.setValue(content);
  }, [content])

  return (
    typeof window !== 'undefined' ? <QuillNoSSRWrapper ref={qRef} modules={modules} value={content} onChange={(c) => setContent(c)} theme="snow" /> : null
  )
}

Use it as

<MyEditor value={data} setValue={setData} />

Comments

1

The solution below fixed it for me. By creating your Editor as a component

import React,{useMemo} from 'react'

import dynamic from "next/dynamic";

type Props = {}

export default function SomePageThatNeedsATextEditor({}: Props) {

const DynamicTextEditor = useMemo(() => {

return dynamic(() => import("@/components/TextEditor"), {

loading: () => <p>loading...</p>,

ssr: false,

});

}, []);

return (

<main>

<DynamicTextEditor prop1={...} prop2={...} />

</main>

)

}

source:https://www.reddit.com/r/nextjs/comments/12hd4h0/how_to_add_react_quill_in_nextjs/

Comments

0

Whenever you encounter the error document is not defined, make sure your JS code is running on client side by making sure that:

  • document is declared within react useEffect hook
  • or by disabling server side rendering by testing first whether document is defined using this way: if ( typeof window !== 'undefined') {run your document code }

and not on server side since document is only defined on client browser.

In next.js 13 this can be done by disabling server sire rendering built in function as below:

    import "quill/dist/quill.snow.css";
    import "react-quill/dist/quill.snow.css"; // Import quill styles
    import dynamic from "next/dynamic";
    
    const ReactQuill = dynamic(import("react-quill"), { ssr: false });
    
    export default function Test() {
      const [text, setText] = useState('');

        return (<div> 
                <div className="form-group">
                              <label htmlFor="address_field">Enter Description
                              </label>
                             
                              <ReactQuill
                                value={text}
                                onChange={(value) => setText(value)}
                                modules={{
                                  toolbar: [
                                    [{ header: [1, 2, false] }],
                                    ["bold", "italic", "underline", "strike"],
                                    ["link"],
                                    [{ align: [] }],
                                    ["blockquote", "code-block"],
                                    [{ list: "ordered" }, { list: "bullet" }],
                                    [{ script: "sub" }, { script: "super" }],
                                  ],
                                }}
                                formats={[
                                  "header",
                                  "bold",
                                  "italic",
                                  "underline",
                                  "strike",
                                  "link",
                                  "align",
                                  "blockquote",
                                  "code-block",
                                  "list",
                                  "bullet",
                                  "script",
                                ]}
                              />
                            </div>
</div>
)}

Comments

0

I used next/dynamic, and it worked fine. you can use this outside the component. like this:

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

And then use this in your component:

const YourComponent = () => {
    const [value, setValue] = useState("");
    return (
        <div>
            {/*... */}
            <ReactQuill theme="snow" value={value} onChange={setValue} />
        </div>
   );
};

You can also use next/dynamic inside your component. you need to memoize the variable in this case.

In both cases it's impotant to use ssr: false in options.

Comments

0

If you need to use Quill from "quill" set it in a seperate component and dynamiclly import that instead. Can be for using multiple editors, etc...

'use client';

import React, { useEffect, useRef } from "react";

import Quill from "quill";

export default function SomeComponent({}: PageProps) {
    const toolbarRef = useRef<HTMLDivElement>(null);
    const editorRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        const createInstance = () => {
            const quillEditor = editorRef.current;
            const quillToolbar = toolbarRef.current;
            if (quillEditor && quillToolbar) {
                editorInstanceRef.current = new Quill(quillEditor, {
                    theme: "snow",
                    modules: { toolbar: quillToolbar },
                });
            }
        };
        createInstance();

    }, []);
    
    
   return (
     <div>
         <div ref={toolbarRef}>
            {/* Your toolbar... */}
         </div>
         <div ref={editorInstanceRef}></div>
     </div>
   )
}


'use client';

import dynamic from 'next/dynamic'
import React, { useMemo } from 'react'

export default function Page() {

    const DynamicTextEditor = useMemo(() => {

        return dynamic(() => import("@/components/SomeComponent"), {
        
        loading: () => <p>loading...</p>,
        
        ssr: false,
        
        });
        
    }, []);
        

  return (
    <div>
        <DynamicTextEditor />
    </div>
  )
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.