react-quill icon indicating copy to clipboard operation
react-quill copied to clipboard

ReactQuill component not appearing in NextJS 13.4.2

Open gurbaaz27 opened this issue 1 year ago • 21 comments

Having an issue with ReactQuill component not appearing in NextJS project using React-Quill v2.0.0, NextJS v13.4.2. After Loading, no component for Quill Editor renders on the screen, and it is surprising me.

Any help would be appreciated.

image

Code

'use client'

import dynamic from "next/dynamic"
import { FieldErrors } from "react-hook-form"

const QuillNoSSRWrapper = dynamic(import('react-quill'), {
    ssr: false,
    loading: () => <p>Loading ...</p>,
})
import 'react-quill/dist/quill.snow.css'

interface QuillEditorProps {
    id: string
    placeholder: string
    onChange: (arg0: string) => void
    value: string
    errors: FieldErrors
}

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'],
        ['clean'],
    ],
    clipboard: {
        // toggle to add extra line breaks when pasting HTML:
        matchVisual: false,
    },
}

const formats = [
    'header',
    'bold', 'italic', 'underline', 'strike', 'blockquote',
    'list', 'bullet', 'indent',
    'link'
]

const QuillEditor: React.FC<QuillEditorProps> = ({
    id,
    placeholder,
    onChange,
    value,
    errors
}) => {
    return (
        <div className='w-full relative block'>
            <QuillNoSSRWrapper
                theme="snow"
                placeholder={placeholder}
                defaultValue={value}
                value={value}
                onChange={(value) => onChange(value)}
                modules={modules}
                formats={formats}
            />
            {errors[id] ? (
                <p className="mt-2 text-pink-600 text-sm">
                    {errors[id]?.message?.toString()}
                </p>
            ) : <></>}
        </div>
    )
}

export default QuillEditor

gurbaaz27 avatar May 26 '23 14:05 gurbaaz27

did you find a solution ?

sohaibMan avatar May 29 '23 15:05 sohaibMan

Nope, hence switched to https://mantine.dev/others/tiptap/ instead.

gurbaaz27 avatar May 29 '23 15:05 gurbaaz27

i have the same problem i need to refresh the page every time for the editor to render

moussaab-moulim avatar Jun 01 '23 20:06 moussaab-moulim

is that in the app directory or the old pages directory?

sohaibMan avatar Jun 02 '23 08:06 sohaibMan

I had the same issue. Then I tried importing ReactQuill without lazy loading it worked for me. Instead of this const Quill = dynamic(import(react-quill), { ssr: false, loading: () => <p>Loading ...</p>, });

Try this import Quill from 'react-quill';

yakkhasuraj avatar Jun 05 '23 16:06 yakkhasuraj

I had the same issue. Then I tried importing ReactQuill without lazy loading it worked for me. Instead of this const Quill = dynamic(import(react-quill), { ssr: false, loading: () => <p>Loading ...</p>, });

Try this import Quill from 'react-quill';

is it working in the app directory?

sohaibMan avatar Jun 05 '23 18:06 sohaibMan

I had the same issue. Then I tried importing ReactQuill without lazy loading it worked for me. Instead of this const Quill = dynamic(import(react-quill), { ssr: false, loading: () => <p>Loading ...</p>, }); Try this import Quill from 'react-quill';

is it working in the app directory?

Yes it's working in the app directory

yakkhasuraj avatar Jun 06 '23 03:06 yakkhasuraj

I have previously solved the following: ` import dynamic from "next/dynamic"

const QuillNoSSRWrapper = dynamic( async () => { const { default: RQ } = await import("react-quill") // eslint-disable-next-line react/display-name return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} /> }, { ssr: false, } )

export const QuillToolbar = () => (

{/* */} {/* */} {/* */} {/* */}
)

export function QuillPage({ value, setValue }: { value: any, setValue: any }) { const dispatch = useDispatch() const dispatchFormData = (data: any) => dispatch(UploadActions.uploadMultiRequest(data))

const multiUploading = useSelector(UploadReducers.multiUploading) const multiUploadResponse = useSelector(UploadReducers.multiUploadResponse)

const editorRef = useRef(null)

const imageHandler = async () => { const input = document.createElement("input") input.setAttribute("type", "file") input.setAttribute("accept", "image/*") input.setAttribute("multiple", "multiple") input.click() input.onchange = async () => { if (input.files) { const listFile = input.files dispatchFormData(listFile) } } } const [isOpen, setIsOpen] = useState(false)

useEffect(() => { if(!multiUploadResponse) return let quillObj = editorRef?.current?.getEditor(); const range = quillObj?.getSelection(); quillObj.editor.insertEmbed(range.index, 'image', multiUploadResponse?.links[0]); }, [multiUploadResponse])

const ImgHandle =() => { return ( <div className="hiii fixed w-screen h-screen bg-primary z-[30000]"> <div className="flex items-center justify-center mx-auto bg-[var(--bg-form)] border-[var(--border-form)] w-[200px] h-[300px]">

pihgadgjgfjg,hdb,jfgjf

) }

const modules = useMemo( () => ({ toolbar: { container: "#toolbar", handlers: { image: imageHandler, // video: handleUploadImagePost }, table: true, }, history: { delay: 500, maxStack: 100, userOnly: true, }, }), [] )

{isOpen===true && (<ImgHandle/>)}

const formats = [ "header", "font", "size", "bold", "italic", "underline", "align", "strike", "script", "blockquote", "background", "list", "bullet", "indent", "link", "video", "image", "color", "code-block", // "table" ]

// useEffect(() => { // if(!multiUploadResponse) return // const quill = editorRef.current.getEditor() // let indexPosition = // }, [multiUploadResponse])

return ( <div className="text-editor relative"> <QuillToolbar /> <QuillNoSSRWrapper forwardedRef={editorRef} value={value} onChange={(value: any) => setValue(value)} placeholder={"Nội dung tối thiểu 100 kí tự"} modules={modules} formats={formats} /> ) }

Add component into your functional: <QuillPage value={value} setValue={setValue} />

`

quang13 avatar Jul 08 '23 16:07 quang13

Fixed my problem

// React Rich Text Editor (Quill)

import dynamic from 'next/dynamic';
import 'react-quill/dist/quill.snow.css';
import type ReactQuill from 'react-quill';
const QuillWrapper = dynamic(
  async () => {
    const { default: RQ } = await import('react-quill');
    // eslint-disable-next-line react/display-name
    return ({ ...props }) => <RQ {...props} />;
  },
  {
    ssr: false,
  }
) as typeof ReactQuill;

violetbee avatar Jul 17 '23 13:07 violetbee

Thanks 👍

aldimenur avatar Aug 11 '23 19:08 aldimenur

This helped me with passing ref (TS, NextJS) https://github.com/zenoamaro/react-quill#methods

import dynamic from 'next/dynamic'
import {useRef, LegacyRef} from 'react'
import type ReactQuill from 'react-quill'

interface IWrappedComponent extends React.ComponentProps<typeof ReactQuill> {
  forwardedRef: LegacyRef<ReactQuill>
}

const ReactQuillBase = dynamic(
  async () => {
    const {default: RQ} = await import('react-quill')

    function QuillJS({forwardedRef, ...props}: IWrappedComponent) {
      return <RQ ref={forwardedRef} {...props} />
    }

    return QuillJS
  },
  {
    ssr: false,
  },
)

export function Editor() {
  const quillRef = useRef<ReactQuill>(null)

  console.log(quillRef.current?.getEditor())

  return (
    <>
      <div>
        <ReactQuillBase forwardedRef={quillRef} />
      </div>
    </>
  )
}

Naksik avatar Aug 17 '23 09:08 Naksik

I had the same issue. Then I tried importing ReactQuill without lazy loading it worked for me. Instead of this const Quill = dynamic(import(react-quill), { ssr: false, loading: () => <p>Loading ...</p>, });

Try this import Quill from 'react-quill';

This worked perfectly fine for me. Thank you.

anroopak avatar Sep 30 '23 17:09 anroopak

Fixed my problem

// React Rich Text Editor (Quill)

import dynamic from 'next/dynamic';
import 'react-quill/dist/quill.snow.css';
import type ReactQuill from 'react-quill';
const QuillWrapper = dynamic(
  async () => {
    const { default: RQ } = await import('react-quill');
    // eslint-disable-next-line react/display-name
    return ({ ...props }) => <RQ {...props} />;
  },
  {
    ssr: false,
  }
) as typeof ReactQuill;

Thanks me a lot :)

Wisesaturn avatar Oct 12 '23 05:10 Wisesaturn

is not woking Cannot read properties of undefined (reading 'prototype') next 13.4

v-kryvenda avatar Nov 06 '23 13:11 v-kryvenda

is not woking Cannot read properties of undefined (reading 'prototype') next 13.4

Same

n8finch avatar Nov 08 '23 21:11 n8finch

is not woking Cannot read properties of undefined (reading 'prototype') next 13.4

Same

Check lib version in packege.json and try to reinstall it.

v-kryvenda avatar Nov 09 '23 06:11 v-kryvenda

Check out my comment with a native solution for next.js

wolfcreative avatar Nov 09 '23 16:11 wolfcreative

I have previously solved the following: ` import dynamic from "next/dynamic"

const QuillNoSSRWrapper = dynamic( async () => { const { default: RQ } = await import("react-quill") // eslint-disable-next-line react/display-name return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} /> }, { ssr: false, } )

export const QuillToolbar = () => (

Arial {/* Comic Sans Courier New Georgia Helvetica Lucida /} Size 1 Size 2 Size 3 Size 4 Heading Subheading Normal {/ /} {/ /} {/ /} {/ /} ) export function QuillPage({ value, setValue }: { value: any, setValue: any }) { const dispatch = useDispatch() const dispatchFormData = (data: any) => dispatch(UploadActions.uploadMultiRequest(data)) const multiUploading = useSelector(UploadReducers.multiUploading) const multiUploadResponse = useSelector(UploadReducers.multiUploadResponse) const editorRef = useRef(null) const imageHandler = async () => { const input = document.createElement("input") input.setAttribute("type", "file") input.setAttribute("accept", "image/") input.setAttribute("multiple", "multiple") input.click() input.onchange = async () => { if (input.files) { const listFile = input.files dispatchFormData(listFile) } } } const [isOpen, setIsOpen] = useState(false) useEffect(() => { if(!multiUploadResponse) return let quillObj = editorRef?.current?.getEditor(); const range = quillObj?.getSelection(); quillObj.editor.insertEmbed(range.index, 'image', multiUploadResponse?.links[0]); }, [multiUploadResponse]) const ImgHandle =() => { return ( pihgadgjgfjg,hdb,jfgjf ) } const modules = useMemo( () => ({ toolbar: { container: "#toolbar", handlers: { image: imageHandler, // video: handleUploadImagePost }, table: true, }, history: { delay: 500, maxStack: 100, userOnly: true, }, }), [] ) {isOpen===true && ()} const formats = [ "header", "font", "size", "bold", "italic", "underline", "align", "strike", "script", "blockquote", "background", "list", "bullet", "indent", "link", "video", "image", "color", "code-block", // "table" ] // useEffect(() => { // if(!multiUploadResponse) return // const quill = editorRef.current.getEditor() // let indexPosition = // }, [multiUploadResponse]) return ( <QuillNoSSRWrapper forwardedRef={editorRef} value={value} onChange={(value: any) => setValue(value)} placeholder={"Nội dung tối thiểu 100 kí tự"} modules={modules} formats={formats} /> ) } Add component into your functional: `

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

export const MainEditor = ({ content, setContent }: any) => { return ( <> <QuillNoSSRWrapper // @ts-ignore theme="snow" value={content} modules={modules} formats={formats} onChange={setContent} placeholder="compose here" /> </> ); };

sam-lukaa avatar Dec 08 '23 20:12 sam-lukaa

I'm not getting default value. How can I fix it? I'm using 14.0.1

rakibulinux avatar Dec 28 '23 05:12 rakibulinux

I can't build reactQuill, It's ok in the dev server but when I try to build it with "yarn build" "it gives an error. Export encountered errors on following paths: /dashboard/settings/page: /dashboard/settings error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.


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

const Settings = () => { const [value, setValue] = useState('');

return ( <ReactQuill theme="snow" value={value} onChange={setValue} className="h-[200px] mb-16" /> ) }

jamilakterup avatar Feb 25 '24 06:02 jamilakterup