Strapi blog logo
  • Product

      Why Strapi?Content ArchitectureRoadmapIntegrationsTry live demo
      OverviewContent Types BuilderCustomizable APIMedia LibraryRoles & Permissions
      Discover Strapi Enterprise EditionDiscover our partners
  • Pricing

  • Solutions

      Static WebsitesMobile ApplicationsCorporate websitesEditorial SitesEcommerce
      Delivery HeroL'EquipeSociete GeneralePixelDustBanco International
      Discover all our user stories
  • Community

      CommunityWrite for the communityWall of LoveStrapi Conf 2021
      SlackGitHubYoutubeCommunity Forum
      Meet the Strapi Community StarsDiscover the Strapi Showcase
  • Resources

      BlogStartersNewsroomSupport
      Strapi AcademyTutorialsVideos GuidesWebinars
      The Guide to Headless CMS Strapi Community Forum
  • Docs

      Getting StartedContent APIConfigurationInstallationDeploymentMigration
      Getting StartedContent ManagerContent-Types BuilderUsers, Roles & PermissionsPlugins
      Developer DocumentationStrapi User Guide

Looking for our logo ?

Logo Brand download
Download Logo Pack
See more Strapi assets
Strapi blog logo
  • Product

    Product

    • Why Strapi?
    • Content Architecture
    • Roadmap
    • Integrations
    • Try live demo

    Features

    • Overview
    • Content Types Builder
    • Customizable API
    • Media Library
    • Roles & Permissions
    • Discover Strapi Enterprise Edition
    • Discover our partners
    Features cover

    Unlock the full potential of content management

    See all features
    Strapi Enterprise Edition

    Discover the advanced features included in Strapi Enterprise Edition.

    Get Started
  • Pricing
  • Solutions

    Solutions

    • Static Websites
    • Mobile Applications
    • Corporate websites
    • Editorial Sites
    • Ecommerce

    Stories

    • Delivery Hero
    • L'Equipe
    • Societe Generale
    • PixelDust
    • Banco International
    • Discover all our user stories
    Delivery Hero team

    Delivery Hero manages their partner portal with Strapi.

    Read their story
    turn 10 studios website

    How 1minus1 delivered a creative website for Turn10 Studios 25% faster with Strapi

    Discover their story
  • Community

    Community

    • Community
    • Write for the community
    • Wall of Love
    • Strapi Conf 2021

    Resources

    • Slack
    • GitHub
    • Youtube
    • Community Forum
    • Meet the Strapi Community Stars
    • Discover the Strapi Showcase
    Strapi Conf

    The first Strapi Global User Conference.

    Register now
    Write for the community

    Contribute on educational content for the community

    Discover the program
  • Resources

    Resources

    • Blog
    • Starters
    • Newsroom
    • Support

    Learning

    • Strapi Academy
    • Tutorials
    • Videos Guides
    • Webinars
    • The Guide to Headless CMS
    • Strapi Community Forum
    Introducing Strapi Academy

    Everything you need to know to master Strapi.

    Go to the academy
    Strapi Repository on GitHub

    Get started with the Strapi repository

    Go to repository
  • Docs

    Developers

    • Getting Started
    • Content API
    • Configuration
    • Installation
    • Deployment
    • Migration

    User Guide

    • Getting Started
    • Content Manager
    • Content-Types Builder
    • Users, Roles & Permissions
    • Plugins
    • Developer Documentation
    • Strapi User Guide
    Install Strapi

    Install Strapi locally or wherever you need.

    Get Started
    Migration Guides Strapi

    Using a previous version of Strapi? Migrate to the latest.

    Read Guides
Get Started
Back to articles

How to change the default WYSIWYG to Quill Editor

How to change the default WYSIWYG to Quill Editor
  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email

Maxime Castres

Many of you don't want to settle for the default WYSIWYG editor in Strapi. This is why you are looking to change the current editor and with any luck you will come across the excellent tutorial from Soupette which teaches you how to change the default editor to CKEditor.

It turns out that, according to our analytics and the number of requests on our slack, this tutorial is highly requested and it's an important resource for you or your team!

It was obvious to offer a second tutorial allowing you, this time, to use the Quill editor, more specifically react-quill. To do this we are going to create a new Field in the administration panel! Nothing very complicated and it won't take you more than 5 min.

Let's dive in!

Note: You should know that quill is an HTML editor and not a Markdown one. Be careful when changing editors on an existing app. If you have existing content in Markdown then you will need to convert it to HTML.

The first thing to do is to take an existing Strapi project. For my part I will simply create a new one.

yarn create strapi-app strapi-quill-editor --quickstart

Now I'm going to create my admin user and a very simple collection-type with just a Rich text field.

Quill-editor-Strapi

Quill-editor-Strapi

Quill-editor-Strapi

Now you can shut down your Strapi server in the terminal by pressing Ctrl+C.

As I said earlier, we are going to create a new Field in the administration panel in order to change our editor. You can find a documentation about this just right here but stick with me, we are going to follow this documentation.

  • Start by generating a new plugin:

yarn strapi generate:plugin wysiwyg

  • Now you need to dive in this plugin folder and to install react-quill:

cd plugins/wysiwyg
yarn add react-quill
  • Perfect! Let's launch our server in --watch-admin for running the front-end development tool

# Go back to the Strapi root folder
cd ../..
yarn develop --watch-admin

Create components

In this part we will create three components:

  • MediaLib which will be used to insert media in the editor
  • Wysiwyg which will wrap the QuillEditor with a label and the errors
  • QuillEditor which will be the implementation of the new WYSIWYG

Create the MediaLib

  • Create a ./plugins/wysiwyg/admin/src/components/MediaLib/index.js file containing the following:

import React, { useEffect, useState } from 'react';
import { useStrapi, prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin';
import PropTypes from 'prop-types';
 
const MediaLib = ({ isOpen, onChange, onToggle }) => {
 const {
   strapi: {
     componentApi: { getComponent },
   },
 } = useStrapi();
 const [data, setData] = useState(null);
 const [isDisplayed, setIsDisplayed] = useState(false);
 
 useEffect(() => {
   if (isOpen) {
     setIsDisplayed(true);
   }
 }, [isOpen]);
 
 const Component = getComponent('media-library').Component;
 
 const handleInputChange = data => {
   if (data) {
     const { url } = data;
 
     setData({ ...data, url: prefixFileUrlWithBackendUrl(url) });
   }
 };
 
 const handleClosed = () => {
   if (data) {
     onChange(data);
   }
 
   setData(null);
   setIsDisplayed(false);
 };
 
 if (Component && isDisplayed) {
   return (
     <Component
       allowedTypes={['images', 'videos', 'files']}
       isOpen={isOpen}
       multiple={false}
       noNavigation
       onClosed={handleClosed}
       onInputMediaChange={handleInputChange}
       onToggle={onToggle}
     />
   );
 }
 
 return null;
};
 
export default MediaLib;

We don't need to change this file! Leave it like this. Let's move on to the next component!

Create the Wrapper

  • Create a ./plugins/wysiwyg/admin/src/components/Wysiwyg/index.js file containing the following:

import React, { useState } from "react";
import PropTypes from "prop-types";
import { Button } from "@buffetjs/core";
import { Label, Description, ErrorMessage } from "@buffetjs/styles";
import Editor from "../QuillEditor";
import MediaLib from "../MediaLib";
 
const Wysiwyg = ({ inputDescription, error, label, name, onChange, value }) => {
  const [isOpen, setIsOpen] = useState(false);
 
  const handleChange = (data) => {
    if (data.mime.includes("image")) {
      const imgTag = `<p><img src="${data.url}" caption="${data.caption}" alt="${data.alternativeText}"></img></p>`;
      const newValue = value ? `${value}${imgTag}` : imgTag;
 
      onChange({ target: { name, value: newValue } });
    }
 
    // Handle videos and other type of files by adding some code
  };
 
  const handleToggle = () => setIsOpen((prev) => !prev);
 
  const hasError = Boolean(error);
 
  return (
    <div
      style={{
        marginBottom: "1.6rem",
        fontSize: "1.3rem",
        fontFamily: "Lato",
      }}
    >
    <div style={{ position: 'absolute', right: '15px', top: '-10px' }}>
      <Button color="primary" onClick={handleToggle}>
        MediaLib
      </Button>
    </div>
      <Label htmlFor={name} style={{ marginBottom: 10 }} >{label} </Label>
 
      <Editor name={name} onChange={onChange} value={value} />
 
      {!hasError && inputDescription && (
        <Description>{inputDescription}</Description>
      )}
      {hasError && <ErrorMessage>{error}</ErrorMessage>}
 
      <MediaLib
        onToggle={handleToggle}
        isOpen={isOpen}
        onChange={handleChange}
      />
    </div>
  );
};
 
export default Wysiwyg;

As you can see we are importing our MediaLib on top of our Editor imported from ../QuillEditor. It doesn't exist yet so let's create it!

Create the Editor

  • Create a ./plugins/wysiwyg/admin/src/components/QuillEditor/index.js file containing the following:

import React, { useState } from "react";
import PropTypes from 'prop-types';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
 
const Editor = ({ onChange, name, value }) => {
 
 const modules = {
   toolbar: [
     [{ 'header': '1'}, {'header': '2'}, { 'font': [] }],
     [{size: []}],
     ['bold', 'italic', 'underline','strike', 'blockquote'],
     [{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
     ['link'],
     ['clean']
   ],
 }
 
 return (
   <ReactQuill
     theme="snow"
     value={value}
     modules={modules}
     onChange={(content, event, editor) => {
       onChange({ target: { name, value: content } });
     }}/>
 );
};
 
export default Editor;

Since the goal of this plugin is to override the current WYSIWYG we don't want it to be displayed in the administration panel but we need it to register our new Field. In order to do so, we will simply modify the front-end entry point of our plugin:

  • Replace the content of your ./plugins/wysiwyg/admin/src/index.js with the following code:
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import App from './containers/App';
import Initializer from './containers/Initializer';
import lifecycles from './lifecycles';
import trads from './translations';

import Wysiwyg from './components/Wysiwyg';

export default strapi => {
  const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
  const icon = pluginPkg.strapi.icon;
  const name = pluginPkg.strapi.name;

  const plugin = {
    blockerComponent: null,
    blockerComponentProps: {},
    description: pluginDescription,
    icon,
    id: pluginId,
    initializer: Initializer,
    injectedComponents: [],
    isReady: false,
    isRequired: pluginPkg.strapi.required || false,
    layout: null,
    lifecycles,
    mainComponent: App,
    name,
    preventComponentRendering: false,
    trads,
    menu: {
      pluginsSectionLinks: [
        {
          destination: `/plugins/${pluginId}`,
          icon,
          label: {
            id: `${pluginId}.plugin.name`,
            defaultMessage: name,
          },
          name,
          permissions: [
            // Uncomment to set the permissions of the plugin here
            // {
            //   action: '', // the action name should be plugins::plugin-name.actionType
            //   subject: null,
            // },
          ],
        },
      ],
    },
  };

  strapi.registerField({ type: 'wysiwyg', Component: Wysiwyg });

  return strapi.registerPlugin(plugin);
};

Here we are basically adding the WYSIWYG component and registering it as a new Field.

If you already know Quill editor, you might see that I didn't import the image module. It is because we are using a button for the MediaLib. Instead of having to click the image button to import all your images, you can simply upload all your assets in the MediaLib and then add them directly to your content using the button on the right side!

  • Now you can stop you server by pressing Ctrl+c and build your admin by running the following command:

yarn build

  • Now you can run your Strapi app:

yarn develop

Quill-editor-Strapi

Quill-editor-Strapi

However if you don't want to use the MediaLib, you simply need to:

  • Remove the ./plugins/wysiwyg/admin/src/components/MediaLib component
  • Remove the component from the Wrapper, here is the code of the wrapper without the MediaLib:

import React, { useState } from "react";
import PropTypes from "prop-types";
import { Button } from "@buffetjs/core";
import { Label, Description, ErrorMessage } from "@buffetjs/styles";
import Editor from "../QuillEditor";
 
const Wysiwyg = ({ inputDescription, error, label, name, onChange, value }) => {
  const [isOpen, setIsOpen] = useState(false);
 
  const handleChange = (data) => {
    if (data.mime.includes("image")) {
      const imgTag = `<p><img src="${data.url}" caption="${data.caption}" alt="${data.alternativeText}"></img></p>`;
      const newValue = value ? `${value}${imgTag}` : imgTag;
 
      onChange({ target: { name, value: newValue } });
    }
 
    // Handle videos and other type of files by adding some code
  };
 
  const handleToggle = () => setIsOpen((prev) => !prev);
 
  const hasError = Boolean(error);
 
  return (
    <div
      style={{
        marginBottom: "1.6rem",
        fontSize: "1.3rem",
        fontFamily: "Lato",
      }}
    >
      <Label htmlFor={name} style={{ marginBottom: 10 }} >{label} </Label>
 
      <Editor name={name} onChange={onChange} value={value} />
 
      {!hasError && inputDescription && (
        <Description>{inputDescription}</Description>
      )}
      {hasError && <ErrorMessage>{error}</ErrorMessage>}
    </div>
  );
};
 
export default Wysiwyg;

Then you simply need to add the image module in the Quill editor by updating the ./plugins/wysiwyg/admin/src/components/QuillEditor/index.js file:

...
const modules = {
   toolbar: [
     [{ 'header': '1'}, {'header': '2'}, { 'font': [] }],
     [{size: []}],
     ['bold', 'italic', 'underline','strike', 'blockquote'],
     [{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
     ['link', 'image'],
     ['clean']
   ],
 }
...
  • Build again your admin by running the following command:

yarn build

  • Run your Strapi app:

yarn develop

Quill-editor-Strapi

That's it! You should be able to use Quill editor now! Thanks for following this tutorial, see you next time ;)

  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email
Restricting Permissions in Strapi Admin Panel 🔐
  • Product

Restricting Permissions in Strapi Admin Panel 🔐

Learn how you can restrict permissions in Strapi Admin Panel 🔐

Cyril Lopez

Cyril Lopez

December 19, 2018

Adding Webhooks in Strapi 🎯
  • Product

Adding Webhooks in Strapi 🎯

Webhooks are already implemented on your favorite headless CMS by now.

Pierre Burgy

Pierre Burgy

October 31, 2018

How to change the WYSIWYG in Strapi
  • Strapi
  • Product

How to change the WYSIWYG in Strapi

This tutorial explains how to easily do an Admin Customization in Strapi. This example shows how to replace the markdown rich text editor by a WYSIWYG editor.

Cyril Lopez

Cyril Lopez

October 23, 2019

Newsletter

Sign up for the Strapi newsletter to keep up with the latest news from the Strapi community!

Unleash content.

Read the docs
Get Started

Strapi is the most popular open-source Headless CMS. Strapi gives developers the freedom to use their favorite tools and frameworks while allowing editors to easily manage their content and distribute it anywhere.

Product

  • Why Strapi?
  • Content Architecture
  • Features
  • Enterprise Edition
  • Partner Program
  • Roadmap
  • Support
  • Integrations
  • Try live demo

Resources

  • How to get started
  • Meet the community
  • Tutorials
  • API documentation
  • GitHub repository
  • Starters
  • Strapi vs Wordpress
  • The Guide to headless CMS

Integrations

  • Gatsby CMS
  • React CMS
  • Vue.js CMS
  • Nuxt.js CMS
  • Next.js CMS
  • Angular CMS
  • Gridsome CMS
  • Jekyll CMS
  • 11ty CMS
  • Svelte CMS
  • Sapper CMS
  • Ruby CMS
  • Python CMS

Company

  • About us
  • Blog
  • Careers
  • Contact
  • Newsroom
  • © 2021, Strapi
  • LicenseTermsPrivacy