Build a Simple Markdown Editor with Next.js

In the digital age, content creation is king. From blog posts and documentation to notes and reports, we constantly generate and consume text. Markdown, a lightweight markup language, has become a favorite for its simplicity and readability. But what if you could create and edit Markdown documents directly in your browser, with a live preview? This article will guide you through building a simple Markdown editor using Next.js, a powerful React framework, enabling you to craft your content with ease and efficiency. This project is perfect for beginners and intermediate developers looking to hone their skills in Next.js and frontend development.

Why Build a Markdown Editor?

Creating a Markdown editor is a fantastic way to learn and practice several key web development concepts. It provides a hands-on opportunity to:

  • Work with user input and state management.
  • Integrate third-party libraries (in this case, for Markdown parsing).
  • Build a dynamic and interactive user interface.
  • Understand and utilize server-side rendering (with Next.js’s capabilities).

Beyond the learning aspect, a Markdown editor is a useful tool. It simplifies content creation, allows for quick formatting, and provides a clear view of how your Markdown will render. Whether you’re a developer, writer, or student, this project can streamline your workflow.

Prerequisites

Before we dive in, ensure you have the following:

  • Node.js and npm (or yarn) installed on your system.
  • A basic understanding of HTML, CSS, and JavaScript.
  • Familiarity with React (though not strictly required, it helps).

Setting Up Your Next.js Project

Let’s get started by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app markdown-editor
cd markdown-editor

This command sets up a new Next.js project named “markdown-editor.” The cd markdown-editor command navigates you into the project directory.

Installing Dependencies

Our Markdown editor will need a library to convert Markdown text into HTML. We’ll use a popular one called ‘marked’. Install it using npm or yarn:

npm install marked
# or
yarn add marked

This command downloads and installs the ‘marked’ library, allowing us to parse Markdown.

Creating the Editor Component

Now, let’s create the core component of our editor. Navigate to the `pages` directory in your project and open `index.js`. Replace the existing content with the following code:

import { useState } from 'react';
import { marked } from 'marked';

export default function Home() {
  const [markdown, setMarkdown] = useState('');

  const handleInputChange = (event) => {
    setMarkdown(event.target.value);
  };

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      <textarea
        style={{
          width: '50%',
          height: '100%',
          padding: '10px',
          boxSizing: 'border-box',
          border: '1px solid #ccc',
        }}
        onChange={handleInputChange}
        value={markdown}
      />
      <div
        style={{
          width: '50%',
          height: '100%',
          padding: '10px',
          boxSizing: 'border-box',
          border: '1px solid #ccc',
          overflow: 'scroll',
          backgroundColor: '#f9f9f9',
        }}
        dangerouslySetInnerHTML={{ __html: marked(markdown) }}
      />
    </div>
  );
}

Let’s break down this code:

  • We import `useState` from React to manage the state of our Markdown text and `marked` from the installed library.
  • `markdown` is the state variable, initialized as an empty string. `setMarkdown` is the function to update it.
  • `handleInputChange` updates the `markdown` state whenever the user types in the textarea.
  • The return statement renders two divs side-by-side:
    • The first is a `textarea` where the user types the Markdown. We use inline styles for basic styling.
    • The second div displays the rendered HTML. `dangerouslySetInnerHTML` is used to inject the HTML generated by `marked(markdown)`. This is safe because the content comes from a trusted source (the user’s input).

Styling the Editor

The inline styles in the code above provide basic styling. However, for a more polished look, you can add CSS. Create a file named `styles/global.css` in your project and add the following:

body {
  margin: 0;
  font-family: sans-serif;
}

textarea {
  font-family: monospace;
  font-size: 14px;
  padding: 10px;
  border: 1px solid #ccc;
  box-sizing: border-box;
  height: 100vh;
}

div {
  padding: 10px;
  border: 1px solid #ccc;
  box-sizing: border-box;
  height: 100vh;
  overflow: scroll;
  background-color: #f9f9f9;
}

Import this CSS file into your `_app.js` file (located in the `pages` directory) to apply the styles globally:

import '../styles/global.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} /gt;
}

export default MyApp

Running Your Application

Save your files and run your Next.js application using the following command in your terminal:

npm run dev
# or
yarn dev

This command starts the development server. Open your browser and go to `http://localhost:3000`. You should see your Markdown editor! Type Markdown in the left panel, and the rendered HTML will appear in the right panel.

Enhancements and Features

Here are some ways to enhance your Markdown editor:

  • Syntax Highlighting: Integrate a library like ‘prismjs’ or ‘highlight.js’ to add syntax highlighting to the rendered HTML code blocks.
  • Toolbar: Add a toolbar with buttons for common Markdown formatting options (bold, italic, headings, etc.).
  • Live Preview: Implement live preview for images and other elements that require external resources.
  • Saving and Loading: Implement functionality to save the Markdown content to local storage or a backend server.
  • Theming: Allow users to switch between light and dark themes.
  • Error Handling: Implement error handling to gracefully handle invalid Markdown or other issues.

Common Mistakes and How to Fix Them

Here are some common pitfalls and how to avoid them:

  • Incorrect Import Paths: Double-check your import paths, especially when importing modules or CSS files. Ensure the paths are relative to the current file.
  • Missing Dependencies: Ensure you have installed all necessary dependencies (e.g., ‘marked’) using npm or yarn.
  • Incorrect HTML Injection: When using `dangerouslySetInnerHTML`, always sanitize your input if it comes from an untrusted source to prevent security vulnerabilities. In this case, since we are only taking input from the user, it is safe.
  • State Updates: Make sure you are correctly updating the state variables using the `set` functions provided by `useState`.
  • CSS Specificity: Be aware of CSS specificity. If your styles aren’t being applied, check if other styles are overriding them. Use the browser’s developer tools to inspect the elements and see which styles are being applied.

Step-by-Step Instructions: A Refresher

Let’s recap the steps to build your Markdown editor:

  1. Set up a Next.js project: Use `npx create-next-app markdown-editor`.
  2. Install ‘marked’: Use `npm install marked` or `yarn add marked`.
  3. Create the editor component: Modify `pages/index.js` as shown in the code above.
  4. Add CSS Styling: Create and import the global CSS file.
  5. Run the development server: Use `npm run dev` or `yarn dev`.
  6. Test your editor: Open `http://localhost:3000` in your browser.
  7. Implement Enhancements: Add features like syntax highlighting, a toolbar, or saving functionality.

Key Takeaways

  • State Management: Understanding and using `useState` is crucial for managing user input and dynamically updating the UI.
  • Third-Party Libraries: Integrating libraries like ‘marked’ simplifies complex tasks and saves development time.
  • Component Structure: Designing your UI with reusable components makes your code more organized and maintainable.
  • CSS Styling: Proper styling enhances the user experience and makes your application visually appealing.
  • Next.js Fundamentals: You’ve gained hands-on experience with core Next.js concepts like routing, component rendering, and server-side rendering.

FAQ

Q: How do I add syntax highlighting to my editor?

A: You can integrate a library like ‘prismjs’ or ‘highlight.js’. Install the library, import its CSS and JavaScript files, and apply it to your rendered HTML code blocks. Often, this involves adding a class to your code blocks, like <code class=”language-javascript”>…</code>.

Q: How can I save the Markdown content?

A: You can use local storage to save the content in the user’s browser or send the content to a backend server to store it in a database. For local storage, use `localStorage.setItem(‘markdown’, markdown)` and `localStorage.getItem(‘markdown’)`. For a backend, you’ll need to create an API endpoint to handle saving the data.

Q: How can I add a toolbar with formatting options?

A: Create a toolbar component with buttons for common Markdown formatting. When a button is clicked, update the `markdown` state by inserting the appropriate Markdown syntax (e.g., `**bold text**` for bold text) at the cursor’s position.

Q: Why is `dangerouslySetInnerHTML` needed?

A: `dangerouslySetInnerHTML` is used because React normally escapes HTML to prevent cross-site scripting (XSS) attacks. However, in this case, we need to inject HTML generated from the Markdown parser. `dangerouslySetInnerHTML` tells React to trust the HTML, but it’s important to be cautious and only use it with trusted content, such as user input in our editor.

Q: How do I deploy this Markdown editor?

A: Next.js makes deployment easy. You can deploy your app to platforms like Vercel (which is built by the Next.js team), Netlify, or other hosting providers that support Node.js applications. Deployment typically involves pushing your code to a repository and configuring the platform to build and deploy your application.

Building a Markdown editor with Next.js is more than just a coding exercise; it’s a gateway to understanding the fundamentals of modern web development. You’ve learned about state management, component composition, and integrating external libraries. You’ve also gained practical experience with a popular framework and a widely used markup language. As you continue to expand your skills, remember that every project, no matter how small, is a step forward. Embrace the process of learning, experimenting, and refining your code. The journey of a thousand lines of code begins with a single Markdown editor.