.Djibril MUG

Edit and preview Markdown in react.js

avatar

Djibril Mug

22 Apr 2023

3 min read


Edit and preview Markdown in react.js

Introduction

For programmers, we all know that markdown is among the best ways for presenting technical documents, but how do proceed if you have to present that document in your project? You may think that it is a very complex task to achieve, but it is much easier than how you can imagine, what you need to do is provide the markdown script and leave the rest to the library.

Create a React app and install dependencies

In this article, we shall be using Vitejs for developing our application since Vite is much faster and very optimized than CreateReactApp, for more information on Vite consult the following resource https://vitejs.dev/guide/ For saving time and effort, we shall be using tailwind-css for styling.

NB: if you are new to Vite you don't need to learn it since all you know is supported and nothing changes.

create a Vite project and download all dependencies

npm create vite@latest markdown-preview -- --template react
cd  markdown-preview
npm i @uiw/react-markdown-preview
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

open your tailwind.config.js and replace all the currents configurations with the following configurations.

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

After applying all the needed configurations go and add the following codes on top of your index.css.

@tailwind base;
@tailwind components;
@tailwind utilities;

Time for previewing Markdown😎



import './App.css'
import React, { useTransition, useState } from "react";
import MarkdownPreview from '@uiw/react-markdown-preview';


function App() {
  const [editorValue, setEditorValue] = useState("");
  const [editorMode, setEditorMode] = useState(true);
  const [activeHeader, setActiveHeader] = useState("editor");
  const [isPending, startTransition] = useTransition();

  const switchEditorMode = (viewMode) => {
    if (viewMode === "editor") {
      setActiveHeader("editor")
      setEditorMode(true)
    } else {
      setActiveHeader("preview")
      startTransition(() => {
        setEditorMode(false)
      })
    }
  }

  return (
    <div className="App w-full min-h-screen bg-gray-100 pt-10">
      <section className="max-w-[900px] relative overflow-hidden min-h-[600px] bg-white rounded-md border m-auto">
        <div className="w-full h-12 top-[0px] left-0 right-0 border-b flex justify-between items-center">
          <div className="flex">
            <div
              style={activeHeader === 'editor' ? {
                background: "#d4d3d3"
              } : {}}
              onClick={() => switchEditorMode("editor")}
              className="w-32 relative flex items-center border-r justify-center  h-12 text-gray-700 cursor-pointer">
              {activeHeader === "editor" && <div className="w-2 h-2 bg-gray-500 border rounded-full gap-2 absolute right-2"></div>}
              <p>Edit</p>
            </div>

            <div style={activeHeader === "preview" ? {
              background: "#d4d3d3"
            } : {}}
              onClick={() => switchEditorMode("preview")}
              className="w-32 relative flex items-center justify-center h-12 text-gray-700 border-r cursor-pointer">
              {activeHeader === "preview" && <div className="w-2 h-2 bg-gray-500 border rounded-full gap-2 absolute right-2"></div>}
              <p>Preview</p>
            </div>
          </div>

          <div className="flex gap-5 px-5">
            <div className="h-4 w-4 bg-green-300 rounded-full "></div>
            <div className="h-4 w-4 bg-blue-500 rounded-full "></div>
            <div className="h-4 w-4 bg-red-300 rounded-full "></div>
          </div>
        </div>


        {/* show loading indicator while switching views  */}
        {isPending ? <p className='m-4'>...loading</p> :
          <>
            {editorMode ?
              //used for collecting markdown scripts
              <section className="px-9 py-5">
                <textarea defaultValue={editorValue} onChange={(e) => setEditorValue(e.target.value)} name="" id="" cols="30" rows="10" className="w-full min-h-[550px] text-sm h-full p-2 outline-none border-none" placeholder="Edit">
                </textarea>
              </section>
              :
              //used for displaying collected markdown scripts 
              <section className="w-full h-full min-h-[600px] px-9 py-5">
                <MarkdownPreview className="markdownPreview" source={editorValue} />
              </section>
            }
          </>

        }
      </section>
    </div>
  )
}

export default App

At the end, this is the final look of the application

Image description

Please note that most of what I include in the above code may not have anything related to markdown preview, but all I wanted is to show how you can use the provided library for real projects and add more optimization.

There are a lot of things you can do uiw/react-markdown-preview library like switching to dark mode and much more here is the link to the official documentation

Bonus All the source codes are available on my GitHub account if you want to have look here is the link to the, repo. And here is the deployed project.