Using React Quill with Zeit Next.js

I decided to use React Quill for a Next.js application I am working on. My goal is to add a Medium-like text editor to my application. I will use the Cloning Medium with Parchment blog post as a guide to achieve my goal. However, for now, let's get started with adding React Quill to a Next.js project.

Styles

Styling React Quill involves importing a stylesheet. That was rather easy after finding this comment on Github. I created a Meta component where I would interact with next/head and injected that into a Page component that surrounds my application in _app.tsx. I stripped a lot of the innards of the following files for brevity but it should work:

Meta.tsx

import Head from "next/head";

const Meta = () => (
  <Head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charSet="utf-8" />
    <link rel="stylesheet" href="//cdn.quilljs.com/1.2.6/quill.snow.css" />
  </Head>
);

export default Meta;

Page.tsx

import React, { Component } from "react";
import Meta from "./Meta";

export default class Page extends Component {
  render() {
    return (
      <>
        <Meta />
        {this.props.children}
      </>
    );
  }
}

\app.tsx_

import App, { Container, NextAppContext } from "next/app";
import Page from "../components/Page";

class MyApp extends App {
  static async getInitialProps({ Component, ctx }: NextAppContext) {
    const pageProps = Component.getInitialProps
      ? await Component.getInitialProps(ctx)
      : {};
    // this exposes the query to the user
    pageProps.query = ctx.query;
    return { pageProps };
  }

  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <Page>
          <Component {...pageProps} />
        </Page>
      </Container>
    );
  }
}

export default MyApp;

Server-Side Rendering

I had to account for Next.js' use of server-side rendering (SSR) when adding React Quill to my project since quill.js is tightly coupled (read: heavily reliant on) the DOM. I found a wonderful comment on a GitHub issue that explained exactly what to do. With this, my simple text input became the following:

TitleInput.tsx

import { Component } from "react";

type TitleInputProps = {
  postTitle: string;
  setPostTitle: (value: string) => void;
};

export default class TitleInput extends Component<TitleInputProps> {
  ReactQuill: any;
  constructor(props: TitleInputProps) {
    super(props);
    if (typeof window !== "undefined") {
      this.ReactQuill = require("react-quill");
    }
  }

  render() {
    const ReactQuill = this.ReactQuill;
    const { postTitle, setPostTitle } = this.props;
    return typeof window !== "undefined" && ReactQuill ? (
      <label>
        Title
        <ReactQuill
          value={postTitle}
          onChange={(content: string) => setPostTitle(content)}
        />
      </label>
    ) : null;
  }
}

This results in a slight flicker in the application but it'll do for the time being.

With that, React Quill should be successfully added to the project. Hopefully I will return with a blog installment about how I successfully managed to make my Quill look like the Medium text editor.

Join My Mailing List

I'm currently working on a Web Development Starter Kit. It will be a pack of content that'll set you on the right path to leave that 💩 job and learn the foundational concepts needed to be a web developer.

For an email on when that's released, join my mailing list!