Custom toolbar: buttons mouse clicks get broken if Quill is re-instantiated
When Quill editor with a custom toolbar is re-instantiated, toolbar buttons get new event listeners added on top of each other, breaking mouse click behaviour.
In our setup, modules need to be updated based on user preferences, which requires re-instantiating Quill, afaik. I opened #4234 to check if it can be avoided, but this current issue seems like a separate bug.
My guess is that since these listeners are added as anonymous functions they are added each time editor is instantiated, rather than being ignored (reference)
Steps for Reproduction
Here's a demo
https://github.com/slab/quill/assets/34838167/ebf4de7c-a2d0-4e34-ba4e-063bbdcfae91
- Visit quilljs playground
- Click "Re-create" button
- Try to mouse-click any formatting button in toolbar
- Check event listeners in dev tools
Expected behavior: Format buttons work as usual
Actual behavior: Format buttons can't be toggled
Platforms: Chrome 125.0.6422.141, MacOS
Version: 2.0.2
I'm also experiencing this issue in my own code. However, when I try your example @ViktorZhurbin it seems to work for me (in Firefox)? In my own code I experience this issue on Firefox.
This also sounds similar to #4360
Quill seems to use eventemitter3 for the event listeners, which states that it should remove all event listeners when off is called. However, that does not seem to happen for some reason?
This also a problem in case you use Quill with React. Since listeners are not cleared, in StrictMode the toolbar will be broken because quill is being initialized twice.
Possible solution until they fix: when you need to re-initialize quill, clone your sidebar using node.clone(true) and replace it with the clone - event listeners will be cleared
In my case using React StricMode leads to toolbar rendering twice. I'm a bit newbie to React so not sure if related. Solved checking if the Quill ref already exists:
function QuillEditorComponent({ value, onChange }) {
const quillRef = useRef(null);
const quillInstance = useRef(null);
useEffect(() => {
// Ensure Quill is only initialized once
if (quillRef.current.className === 'ql-container ql-snow') return;
// Initialize Quill instance
quillInstance.current = new Quill(quillRef.current, {
theme: 'snow', // Use the "snow" theme
placeholder,
modules: {
toolbar: [
['bold', 'italic', 'underline', 'strike'],
[{ list: 'ordered' }, { list: 'bullet' }],
],
},
});
// ...