reactjsnext.jsquillreact-quill

How to apply inline styles instead of Quill classes in ReactQuill (Next.js)?


I am using react-quill-new in my Next.js project and want to apply inline styles instead of Quill's default class-based styles (e.g., ql-align-center). When I send my content as an HTML email, the styles don’t apply because they are class-based.

I have already tried setting matchVisual: false inside the clipboard module, but the output still contains class-based styles instead of inline styles.

Here is my current Editor component:

'use client'

import dynamic from "next/dynamic"; import "./EditorStyle/bubble.css"; import Quill from "quill";

const ReactQuill = dynamic(() => import("react-quill-new"), { ssr: false });

export const Editor = ({ content, onChange, className }: { content: any, className: string, onChange: (value: string) => void }) => {

    const module = {
        toolbar: {
            container: [
                [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
                ["bold", "italic", "underline"],
                ['link'],
                [{ 'list': 'ordered' }, { 'list': 'bullet' }],
                [{ 'color': [] }, { 'background': [] }],
                ['clean'],
                [{ 'font': [] }],
                [{ 'align': [] }],
            ],
            handlers: {
                link: function(value: string) {
                    const that: any = this;
                    const tooltip = that.quill.theme.tooltip;
                    const input = tooltip.root.querySelector("input[data-link]");
                    input.dataset.link = "google.com";
    
                    if (value) {
                        const range = that.quill.getSelection();
                        if (range == null || range.length === 0) {
                            return;
                        }
                        let preview = '';
                        if (/^\S+@\S+\.\S+$/.test(preview) && preview.indexOf("mailto:") !== 0) {
                            preview = `mailto:${preview}`;
                        }
                        const { tooltip } = that.quill.theme;
                        tooltip.edit("link", preview);
                    } else {
                        that.quill.format("link", false);
                    }
                }
            }
        },
        clipboard: {
            matchVisual: false
        }
    };
    
    return (
        <div>
            <div>
                <ReactQuill
                    theme="bubble"
                    value={content}
                    modules={module}
                    placeholder="Write something amazing..."
                    onChange={onChange}
                    className={`${className}`}
                />
            </div>
        </div>
    );
    
};`

I want to ensure that:

  1. Alignment (e.g., center, left, right) is applied using inline styles like style="text-align: center;" instead of class="ql-align-center".

  2. Lists, colors, fonts, and other styles also use inline styles.

How can I modify my Quill configuration to achieve this? Thanks in advance!

I tried using the formats prop in ReactQuill to specify formatting options explicitly, but it didn’t make a difference—the output still contained class-based styles like ql-align-center instead of inline styles.

I also set matchVisual: false in the clipboard module, hoping it would force Quill to apply inline styles instead of classes, but that didn’t work either.

I expected Quill to apply styles directly to the elements using inline attributes like style="text-align: center;" instead of relying on external CSS classes. However, when I check the generated HTML, it still uses class="ql-align-center", which doesn’t work properly in email clients.

I'm looking for a way to modify my configuration so that all styles (alignment, colors, lists, fonts, etc.) are applied as inline styles instead of classes.


Solution

  • Register style-based attributors for alignment, background, color, font, and size instead of using class-based ones.

    Override Quill's default behavior.

    Add formats prop to explicitly specify which formats should be available.

    'use client'
    
    import dynamic from "next/dynamic";
    import "./EditorStyle/bubble.css";
    import Quill from "quill";
    import { useMemo } from "react";
    
    const ReactQuill = dynamic(() => import("react-quill-new"), { ssr: false });
    
    // Custom alignment style
    const AlignStyle = Quill.import('attributors/style/align');
    Quill.register(AlignStyle, true);
    
    // Custom background style
    const BackgroundStyle = Quill.import('attributors/style/background');
    Quill.register(BackgroundStyle, true);
    
    // Custom color style
    const ColorStyle = Quill.import('attributors/style/color');
    Quill.register(ColorStyle, true);
    
    // Custom font style
    const FontStyle = Quill.import('attributors/style/font');
    Quill.register(FontStyle, true);
    
    // Custom size style
    const SizeStyle = Quill.import('attributors/style/size');
    Quill.register(SizeStyle, true);
    
    export const Editor = ({ content, onChange, className }: { 
      content: any, 
      className: string, 
      onChange: (value: string) => void 
    }) => {
      const modules = useMemo(() => ({
        toolbar: {
          container: [
            [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
            ["bold", "italic", "underline"],
            ['link'],
            [{ 'list': 'ordered' }, { 'list': 'bullet' }],
            [{ 'color': [] }, { 'background': [] }],
            ['clean'],
            [{ 'font': [] }],
            [{ 'align': [] }],
          ],
          handlers: {
            link: function(value: string) {
              const that: any = this;
              const tooltip = that.quill.theme.tooltip;
              const input = tooltip.root.querySelector("input[data-link]");
              input.dataset.link = "google.com";
    
              if (value) {
                const range = that.quill.getSelection();
                if (range == null || range.length === 0) {
                  return;
                }
                let preview = '';
                if (/^\S+@\S+\.\S+$/.test(preview) && preview.indexOf("mailto:") !== 0) {
                  preview = `mailto:${preview}`;
                }
                const { tooltip } = that.quill.theme;
                tooltip.edit("link", preview);
              } else {
                that.quill.format("link", false);
              }
            }
          }
        },
        clipboard: {
          matchVisual: false
        }
      }), []);
    
      const formats = [
        'align',
        'background',
        'bold',
        'color',
        'font',
        'header',
        'italic',
        'link',
        'list',
        'underline',
        'size'
      ];
    
      return (
        <div>
          <div>
            <ReactQuill
              theme="bubble"
              value={content}
              modules={modules}
              formats={formats}
              placeholder="Write something amazing..."
              onChange={onChange}
              className={`${className}`}
            />
          </div>
        </div>
      );
    };