Search code examples
reactjsquillreactjs-popupreact-quilljs

react-quilljs and reactjs-popup don't work together


I'm using react-quilljs and reactjs-popup together and can't get the quill-based editor to show in my modal dialog. I can use the editor on the main page with no issues but it will not work on the popup.

I have the expected imports:

import React from "react";
import Popup from "reactjs-popup";
import "reactjs-popup/dist/index.css";
import { useQuill } from "react-quilljs";

And my component looks something like this:

const NewIdeaDialog = ({ showNewIdea }) => {
  const { quill, quillRef } = useQuill();
  return (
    <Popup open={showNewIdea} nested>
      <div>
        <form action="" method="">
          <label for="IdeaDetails">Details</label>
          <div style={{ width: 500, height: 300 }} id="IdeaDetails">
            <div ref={quillRef} />
          </div>
        </form>
      </div>
    </Popup>
  );
}

When I set showNewIdea to true in the parent component the popup is displayed, as expected, but the quill editor is completely missing. It renders the #IdeaDetails div and a child that is <div></div> and that's all. The child div is completely empty and devoid of styling.

Am I missing something that will make this work? I can't find any similar issues listed on the web for this problem.


Solution

  • It's working just right

    enter image description here

    with qill css too

    import 'quill/dist/quill.snow.css';
    

    The same code is working perfectly

    import React from "react";
    import Popup from "reactjs-popup";
    import "reactjs-popup/dist/index.css";
    import { useQuill } from "react-quilljs";
    import './App.css';
    import 'quill/dist/quill.snow.css'; // <<<====
    
    function App({showNewIdea}) {
      const { quill, quillRef } = useQuill();
      return (
        <Popup open={true} nested> {/* <======= set to true */}
          <div>
            <form action="" method="">
              <label for="IdeaDetails">Details</label>
              <div style={{ width: 500, height: 300 }} id="IdeaDetails">
                <div ref={quillRef} />
              </div>
            </form>
          </div>
        </Popup>
      );
    }
    
    export default App;
    

    Wait it worked because show is true

    The code above work because the popup show, is set to true!

    So if the Popup state change it will not work!

    Solution: Something that works

    As @Software Engineer! Mentionned in the comment! He asked the author of the library! you can check here

    A solution that works! Is to wrap the elements that go within the Popup! On there own component! And initiate quil there! Throught the useQuill hook!

    import "reactjs-popup/dist/index.css";
    import "quill/dist/quill.snow.css"; // Add css for snow theme
    // or import 'quill/dist/quill.bubble.css'; // Add css for bubble theme
    
    export default () => {
      const [showNewIdea, setShowNewIdea] = useState(false);
    
      const togglePopup = () => setShowNewIdea(!showNewIdea);
    
      return (
        <div>
          <input type="button" value="open" onClick={togglePopup} />
          <Popup open={showNewIdea} nested>
            <NewIdeaDialog />
          </Popup>
        </div>
      );
    };
    
    const NewIdeaDialog = () => {
      const { quillRef } = useQuill();
      return (
        <div>
          <form action="" method="" style={{ width: "100%", height: "100%" }}>
            <label for="IdeaDetails">Details</label>
            <div style={{ width: "100%", height: "100%" }} id="IdeaDetails">
              <div ref={quillRef} />
            </div>
          </form>
        </div>
      );
    };
    

    You can check the playground here! That include to debug! And undestand why!

    What was the problem and what we can learn from this

    This answer is not finished! This section will be updated later! (i'll share both some observations! And explain the why) (you may check later)

    Quill hook function

    export const useQuill = (options: QuillOptionsStatic | undefined = { theme, modules, formats }) => {
      const quillRef: RefObject<any> = useRef();
    
      const [isLoaded, setIsLoaded] = useState(false);
      const [obj, setObj] = useState({
        Quill: undefined as any | undefined,
        quillRef,
        quill: undefined as Quill | undefined,
        editorRef: quillRef,
        editor: undefined as Quill | undefined,
      });
    
      useEffect(() => {
        if (!obj.Quill) { obj.Quill = require('quill') as Quill; }
        if (obj.Quill && !obj.quill && quillRef && quillRef.current && isLoaded) {
          const opts = assign(options, {
            modules: assign(modules, options.modules),
            formats: options.formats || formats,
            theme: options.theme || theme,
          })
          const quill = new obj.Quill(quillRef.current, opts);
    
          setObj(assign(assign({}, obj), { quill, editor: quill }));
        }
        setIsLoaded(true);
      }, [obj.Quill]);
    
      return obj;
    };
    

    First implementation

    enter image description here

    Separate component

    enter image description here

    Expect update for the explanation of how and why! And the details!