Reputation: 411
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>
)
}
Upvotes: 9
Views: 11184
Reputation: 153
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>
)
}
Upvotes: 0
Reputation: 41
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.
Upvotes: 0
Reputation: 1243
[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} />
Upvotes: 3
Reputation: 49
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/
Upvotes: 1
Reputation: 805
Whenever you encounter the error document is not defined, make sure your JS code is running on client side by making sure that:
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>
)}
Upvotes: 0
Reputation: 706
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;
Upvotes: 43