In today’s fast-paced digital world, the ability to create and edit formatted text is a fundamental skill. Whether you’re a student, a writer, or a developer, a reliable markdown editor can significantly streamline your workflow. Markdown, a lightweight markup language, allows you to format text using simple syntax, making it easy to create visually appealing documents without the complexities of HTML. In this tutorial, we’ll dive into building a fully functional, interactive Markdown editor using Next.js, a powerful React framework for building modern web applications. This project will not only teach you the fundamentals of Next.js but also equip you with the skills to create a practical and useful tool.
Why Build a Markdown Editor?
While numerous online markdown editors exist, building your own offers several advantages. Firstly, it provides a deep understanding of how markdown works and how to implement it within a web application. Secondly, you gain complete control over the features and customization options, tailoring the editor to your specific needs. Thirdly, it’s an excellent learning experience, allowing you to explore concepts like state management, event handling, and real-time updates in a practical context. Finally, it’s a valuable addition to your portfolio, showcasing your ability to build interactive web applications.
Prerequisites
Before we begin, ensure you have the following installed on your system:
- Node.js (version 14 or higher)
- npm or yarn (package managers)
- A code editor (e.g., VS Code, Sublime Text)
Basic knowledge of HTML, CSS, and JavaScript is also helpful, as Next.js builds upon these foundational web technologies.
Setting Up Your Next.js Project
Let’s start by creating a new Next.js project. Open your terminal and run the following command:
npx create-next-app markdown-editor
This command sets up a new Next.js project named “markdown-editor.” Navigate into the project directory:
cd markdown-editor
Next, start the development server:
npm run dev
or
yarn dev
Open your web browser and go to http://localhost:3000. You should see the default Next.js welcome page.
Installing Dependencies
We’ll need a few dependencies for our markdown editor:
react-markdown: This library will handle the conversion of Markdown text to HTML.remark-gfm: This plugin adds support for GitHub Flavored Markdown (GFM) features like tables and task lists.
Install these dependencies using npm or yarn:
npm install react-markdown remark-gfm
or
yarn add react-markdown remark-gfm
Building the Editor Component
Now, let’s create the core component for our markdown editor. We’ll create a new file named Editor.js in the components directory (you may need to create this directory). If you don’t have a components directory, create one.
Here’s the code for Editor.js:
import React, { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import { remarkGfm } from 'remark-gfm';
function Editor() {
const [markdown, setMarkdown] = useState('');
const handleChange = (event) => {
setMarkdown(event.target.value);
};
return (
<div>
<div>
<textarea />
</div>
<div>
{markdown}
</div>
</div>
);
}
export default Editor;
Let’s break down this code:
- We import
useStatefrom React to manage the state of our markdown text. - We import
ReactMarkdownto render the markdown. - We import
remarkGfmto enable GFM features. - We define a functional component called
Editor. - We use
useStateto create a state variable calledmarkdown, initialized to an empty string. This variable holds the markdown text entered by the user. - The
handleChangefunction updates themarkdownstate whenever the user types in the textarea. - The component returns a
divwith two childdivs: one for the input (textarea) and one for the output (rendered HTML). - The
textareais bound to themarkdownstate and callshandleChangeon input. ReactMarkdownrenders themarkdownstate as HTML, using theremarkGfmplugin.
Styling the Editor
To make the editor visually appealing, let’s add some basic CSS. Create a file named Editor.module.css in the components directory (or another CSS file, as you prefer) and add the following styles:
.editor-container {
display: flex;
flex-direction: row;
width: 100%;
height: 80vh;
}
.input-container {
flex: 1;
padding: 20px;
background-color: #f0f0f0;
}
.input-textarea {
width: 100%;
height: 100%;
padding: 10px;
border: 1px solid #ccc;
font-family: monospace;
resize: none;
}
.output-container {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: #fff;
}
Now, import the CSS module into your Editor.js file:
import React, { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import { remarkGfm } from 'remark-gfm';
import styles from './Editor.module.css'; // Import the CSS module
function Editor() {
const [markdown, setMarkdown] = useState('');
const handleChange = (event) => {
setMarkdown(event.target.value);
};
return (
<div>
<div>
<textarea />
</div>
<div>
{markdown}
</div>
</div>
);
}
export default Editor;
Note how we’ve used the imported styles object to apply the CSS classes to our elements.
Integrating the Editor into Your Page
Now, let’s integrate the Editor component into our main page (pages/index.js). Open pages/index.js and replace the existing content with the following:
import Editor from '../components/Editor';
function HomePage() {
return (
<div>
</div>
);
}
export default HomePage;
This imports the Editor component and renders it within the page.
Now, if you refresh your browser, you should see the Markdown editor. As you type in the left-hand textarea, the formatted output will appear in the right-hand panel.
Adding More Features
Our basic editor is functional, but let’s enhance it with some additional features:
1. Live Preview
The live preview is already working, thanks to ReactMarkdown updating in real time as the state changes.
2. Syntax Highlighting
For syntax highlighting, we can use a library like prismjs. First, install it:
npm install prismjs
or
yarn add prismjs
Then, modify the Editor.js file to import and use Prism:
import React, { useState, useEffect } from 'react';
import ReactMarkdown from 'react-markdown';
import { remarkGfm } from 'remark-gfm';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { dark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import styles from './Editor.module.css';
function Editor() {
const [markdown, setMarkdown] = useState('');
const handleChange = (event) => {
setMarkdown(event.target.value);
};
return (
<div>
<div>
<textarea />
</div>
<div>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(w+)/.exec(className || '');
return !inline && match ? (
) : (
<code>
{children}
);
},
}}
>
{markdown}
