Skip to content

omotsuebe/react-quill-editor

Repository files navigation

Quill Editor for React with TypeScript

Introduction

This project provides a modern Quill editor implementation for React using TypeScript. This is a fresh implementation of Quill for React using TypeScript, inspired by the official Quill playground (https://quilljs.com/playground/react), offering better compatibility and flexibility.

Quill Editor

Features

  • Fully compatible with React 18/19+

  • Built using TypeScript for strong typing

  • Supports custom toolbar options

  • Provides full control over Quill’s lifecycle

  • Lightweight and efficient state management

Installation

Ensure you have a React project set up, then install Quill:

npm install quill

Usage

1. Import the Custom Editor Component

Example: Create a file App.tsx and use the custom Quill editor.

import { useState } from 'react';
import CustomEditor from './editor/custom-editor';
import './App.css';

function App() {
  const [editorContent, setEditorContent] = useState('');

  const handleEditorChange = (content: string) => {
    setEditorContent(content);
  };

  return (
    <div className="app-container">
      <h1>Quill Editor Example for React</h1>
      <div className="editor-wrapper">
        <CustomEditor
          value={editorContent}
          onChange={handleEditorChange}
          placeholder="Start writing your content here..."
          readOnly={false}
        />
      </div>
    </div>
  );
}

export default App;

2. Implement the Custom Quill Editor

Create editor/custom-editor.tsx and initialize Quill dynamically. The complete code is located in editor/ folder

import { forwardRef, useEffect, useRef, useState } from 'react';
import Quill from 'quill';
import 'quill/dist/quill.snow.css';
import './custom-editor.css';

interface CustomEditorProps {
  value?: string;
  onChange?: (content: string) => void;
  readOnly?: boolean;
  placeholder?: string;
}

const CustomEditor = forwardRef<Quill, CustomEditorProps>(({ value = '', onChange, readOnly = false, placeholder = 'Write something...' }, ref) => {
  const editorRef = useRef<HTMLDivElement>(null);
  const quillRef = useRef<Quill | null>(null);
  const [editorId] = useState(`quill-editor-${Math.random().toString(36).substring(2, 9)}`);

  useEffect(() => {
    const destroyQuill = () => {
      if (quillRef.current) {
        quillRef.current = null;
      }
      document.querySelectorAll('.ql-toolbar').forEach(toolbar => toolbar.remove());
      if (editorRef.current) {
        editorRef.current.innerHTML = '';
        const editorElement = document.createElement('div');
        editorElement.id = editorId;
        editorRef.current.appendChild(editorElement);
        return editorElement;
      }
      return null;
    };

    const editorElement = destroyQuill();
    if (!editorElement) return;

    const modules = {
      toolbar: [
        [{ 'header': [1, 2, 3, false] }],
        ['bold', 'italic', 'underline'],
        [{ 'list': 'ordered' }, { 'list': 'bullet' }],
      ],
    };

    quillRef.current = new Quill(editorElement, {
      theme: 'snow',
      modules,
      placeholder,
      readOnly,
    });

    quillRef.current.on('text-change', () => {
      if (onChange) onChange(quillRef.current!.root.innerHTML);
    });
  }, []);

  return <div ref={editorRef} className="custom-editor-container" />;
});

export default CustomEditor;

Styles

Add the following styles in editor/custom-editor.css:

/* Quill specific styles */
.ql-toolbar.ql-snow {
    border: none !important;
    border-bottom: 1px solid #ccc !important;
    border-radius: 4px 4px 0 0;
}

.ql-container.ql-snow {
    border: none !important;
    min-height: 300px;
}

.quill-editor {
    min-height: 300px;
}

.preview-section {
    margin-top: 2rem;
    padding: 1rem;
    border: 1px solid #eee;
    border-radius: 4px;
    background: white;
}

.preview-section h2 {
    margin-top: 0;
    color: #333;
}

Contributing

Contributions are welcome! Feel free to submit a pull request or open an issue.

License

This project is licensed under the MIT License.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published