I am using React Quill as the text editor. This works fine until I add the custom image handler. If I add the image handler as below, I can't type into the editor. Typing lose focus on every single keypress.
const modules = {
toolbar: {
container: [
[{'header': [3, 4, 5, 6, false]}],
['bold', 'italic', 'underline', 'strike', 'blockquote', 'code'],
[{color: []}, {background: []}],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean']
],
handlers: {
image: imageHandler
}
},
clipboard: {
// toggle to add extra line breaks when pasting HTML:
matchVisual: false,
}
};
function imageHandler() {
console.log("custom image handler");
}
If I comment out the image: imageHandler
, editor works perfectly. Here is the codesanbox example
Am I writing the custom module correctly?
I am using React Quill as the text editor. This works fine until I add the custom image handler. If I add the image handler as below, I can't type into the editor. Typing lose focus on every single keypress.
const modules = {
toolbar: {
container: [
[{'header': [3, 4, 5, 6, false]}],
['bold', 'italic', 'underline', 'strike', 'blockquote', 'code'],
[{color: []}, {background: []}],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean']
],
handlers: {
image: imageHandler
}
},
clipboard: {
// toggle to add extra line breaks when pasting HTML:
matchVisual: false,
}
};
function imageHandler() {
console.log("custom image handler");
}
If I comment out the image: imageHandler
, editor works perfectly. Here is the codesanbox example
Am I writing the custom module correctly?
Share Improve this question asked Jan 20, 2020 at 14:35 The CoderThe Coder 4,02710 gold badges52 silver badges85 bronze badges 7- Just wondering if you're using react-quill for a new project? We've been using it on our app over the last few years and it has been very poorly supported. I'd steer clear from it if possible. – William Park Commented Jan 20, 2020 at 16:23
- @WilliamPark Yes it's a new project. what would you recommend? All open source text editors have poor support. – The Coder Commented Jan 20, 2020 at 18:40
- Take a look at Draft or Slate. I'm in the process of switching quill over to a slate editor. – William Park Commented Jan 21, 2020 at 9:21
- @WilliamPark if you are concerned about "it has been very poorly supported", then you should remove 'draft.js' from the list. Other options you may consider are: Nib(nibedit.com) and Article editor(paid, imperavi.com/article) – The Coder Commented Jan 22, 2020 at 4:56
- Yeah Draft hasn't been well supported lately either, that is totally fair. It has had commits over the last few months unlike react-quill that hasn't received any in years. We have went with Slate. It's a bit more work to set up but it feels very flexible in its capabilities. – William Park Commented Jan 22, 2020 at 9:57
2 Answers
Reset to default 22TL;DR
This is what helped me:
https://github.com/zenoamaro/react-quill/issues/309#issuecomment-654768941 https://github.com/zenoamaro/react-quill/issues/309#issuecomment-659566810
The modules object passed directly into the component makes it render all modules on every keypress. To make it stop, you have to use the concept of memoization in react. You can use the useMemo hook to wrap the modules and then pass that into the component.
const modules = useMemo(() => ({
toolbar: {
container: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
[{ list: 'ordered' }, { list: 'bullet' }],
['image', 'code-block']
],
handlers: {
image: selectLocalImage
}
}
}), [])
and then in the component:
<ReactQuill placeholder="Write some text..."
value={text}
modules={modules}
onChange={onChange} />
useRef() & onBlur()
is the Ultimate answer to your question.
Here is how I solved the same query.
export default function QuillEditor({
value,
onChange
}) {
const [description, setDescription] = useState(value || "");
useEffect(() => {
if (value) {
setDescription(value);
}
}, [value]);
....
const quillRef = useRef(); // the solution
....
const imageHandler = () => {
// get editor
const editor = quillRef.current.getEditor();
const input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click();
input.onchange = async () => {
const file = input.files[0];
try {
const link = IMAGE_LINK_HERE;
editor.insertEmbed(editor.getSelection(), "image", link);
} catch (err) {
console.log("upload err:", err);
}
};
};
const toolbarOptions = [
["bold", "italic", "underline", "strike"],
["code-block", "link", "image"],
...
];
const modules = {
toolbar: {
container: toolbarOptions,
handlers: {
image: imageHandler,
},
},
clipboard: {
matchVisual: false,
},
};
const handleOnBlur = () => {
onChange(description);
};
....
return (
<ReactQuill
ref={quillRef} // must pass ref here
value={description}
onChange={(val) => setDescription(val)}
onBlur={handleOnBlur}
theme="snow"
modules={modules}
formats={formats}
placeholder="Write something awesome..."
/>
)
....