We use cookies to enhance your experience on the site
CodeWorlds

Markdown Support - Formatted Text

Reddit lets users format posts using Markdown. Let's learn to handle it in Next.js!

What is Markdown? 📝

Markdown is a simple text formatting language:

1# Heading 1
2## Heading 2
3
4**bold** and *italic*
5
6- Bulleted
7- List
8
9[Link](https://example.com)
10
11```code```

Why Markdown?

  • ✅ Easy to learn
  • ✅ Readable in raw form
  • ✅ Safer than HTML
  • ✅ Used by GitHub, Reddit, Discord

Library: react-markdown 📚

Install:

1npm install react-markdown

Basic usage:

1import ReactMarkdown from 'react-markdown';
2
3function Post({ content }: { content: string }) {
4  return (
5    <div className="prose">
6      <ReactMarkdown>{content}</ReactMarkdown>
7    </div>
8  );
9}
10
11// Usage
12const markdown = \`
13# Pirate's Tale
14
15This is **bold** and this is *italic*.
16
17- Rum
18- Treasure
19- Adventure
20
21[Black Pearl](https://example.com)
22\`;
23
24<Post content={markdown} />

Styling Markdown - Tailwind Typography 🎨

Tailwind has a

@tailwindcss/typography
plugin that styles Markdown automatically!

Installation:

1npm install @tailwindcss/typography

Configuration -
tailwind.config.ts
:

1module.exports = {
2  plugins: [
3    require('@tailwindcss/typography'),
4  ],
5}

Usage -
prose
class:

1<div className="prose prose-blue max-w-none">
2  <ReactMarkdown>{content}</ReactMarkdown>
3</div>

Prose classes:

  • prose
    - default styles
  • prose-sm
    - smaller text
  • prose-lg
    - larger text
  • prose-blue
    - blue links
  • prose-invert
    - for dark mode
  • max-w-none
    - remove max-width

Markdown Editor - Live Preview 👁️

Let's create an editor with live preview:

1import { useState } from 'react';
2import ReactMarkdown from 'react-markdown';
3
4function MarkdownEditor() {
5  const [markdown, setMarkdown] = useState(`# Hello Pirates!
6
7Write your **markdown** here...
8
9- Feature 1
10- Feature 2
11`);
12
13  return (
14    <div className="grid grid-cols-2 gap-4 h-screen">
15      {/* Editor */}
16      <div>
17        <h2 className="font-bold mb-2">Editor</h2>
18        <textarea
19          value={markdown}
20          onChange={(e) => setMarkdown(e.target.value)}
21          className="w-full h-full border rounded p-4 font-mono"
22        />
23      </div>
24
25      {/* Preview */}
26      <div>
27        <h2 className="font-bold mb-2">Preview</h2>
28        <div className="prose border rounded p-4 h-full overflow-auto">
29          <ReactMarkdown>{markdown}</ReactMarkdown>
30        </div>
31      </div>
32    </div>
33  );
34}

Syntax Highlighting - Code Blocks 🌈

For code blocks use

react-syntax-highlighter
:

1npm install react-syntax-highlighter
2npm install @types/react-syntax-highlighter

Custom components:

1import ReactMarkdown from 'react-markdown';
2import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
3import { tomorrow } from 'react-syntax-highlighter/dist/cjs/styles/prism';
4
5function MarkdownPost({ content }: { content: string }) {
6  return (
7    <ReactMarkdown
8      components={{
9        code({ node, inline, className, children, ...props }) {
10          const match = /language-(w+)/.exec(className || '');
11          return !inline && match ? (
12            <SyntaxHighlighter
13              style={tomorrow}
14              language={match[1]}
15              PreTag="div"
16              {...props}
17            >
18              {String(children).replace(/
19$/, '')}
20            </SyntaxHighlighter>
21          ) : (
22            <code className={className} {...props}>
23              {children}
24            </code>
25          );
26        }
27      }}
28    >
29      {content}
30    </ReactMarkdown>
31  );
32}

Sanitization - Security 🛡️

Warning: Markdown can contain malicious HTML/JS!

Use
remark-gfm
and
rehype-sanitize
:

1npm install remark-gfm rehype-sanitize
1import ReactMarkdown from 'react-markdown';
2import remarkGfm from 'remark-gfm';
3import rehypeSanitize from 'rehype-sanitize';
4
5function SafeMarkdown({ content }: { content: string }) {
6  return (
7    <ReactMarkdown
8      remarkPlugins={[remarkGfm]}
9      rehypePlugins={[rehypeSanitize]}
10    >
11      {content}
12    </ReactMarkdown>
13  );
14}

remarkGfm adds GitHub Flavored Markdown (tables, task lists) rehypeSanitize removes malicious HTML

Markdown Toolbar - Helper Buttons 🔧

Add a toolbar for inserting Markdown:

1function MarkdownToolbar({ onInsert }: { onInsert: (text: string) => void }) {
2  return (
3    <div className="flex gap-2 mb-2 border-b pb-2">
4      <button onClick={() => onInsert('**bold**')} className="px-2 py-1 hover:bg-gray-100 rounded">
5        <strong>B</strong>
6      </button>
7      <button onClick={() => onInsert('*italic*')} className="px-2 py-1 hover:bg-gray-100 rounded">
8        <em>I</em>
9      </button>
10      <button onClick={() => onInsert('[link](url)')} className="px-2 py-1 hover:bg-gray-100 rounded">
11        🔗
12      </button>
13      <button onClick={() => onInsert('`code`')} className="px-2 py-1 hover:bg-gray-100 rounded font-mono">
14        &lt;/&gt;
15      </button>
16      <button onClick={() => onInsert('- List item')} className="px-2 py-1 hover:bg-gray-100 rounded">
17List
18      </button>
19    </div>
20  );
21}
22
23function MarkdownEditor() {
24  const [markdown, setMarkdown] = useState("");
25  const textareaRef = useRef<HTMLTextAreaElement>(null);
26
27  const handleInsert = (text: string) => {
28    const textarea = textareaRef.current;
29    if (!textarea) return;
30
31    const start = textarea.selectionStart;
32    const end = textarea.selectionEnd;
33    const before = markdown.substring(0, start);
34    const after = markdown.substring(end);
35
36    setMarkdown(before + text + after);
37
38    // Focus and select inserted text
39    setTimeout(() => {
40      textarea.focus();
41      textarea.setSelectionRange(start, start + text.length);
42    }, 0);
43  };
44
45  return (
46    <div>
47      <MarkdownToolbar onInsert={handleInsert} />
48      <textarea
49        ref={textareaRef}
50        value={markdown}
51        onChange={(e) => setMarkdown(e.target.value)}
52        className="w-full h-64 border rounded p-4 font-mono"
53      />
54      <div className="prose mt-4">
55        <ReactMarkdown>{markdown}</ReactMarkdown>
56      </div>
57    </div>
58  );
59}

Summary 🎓

Markdown - simple formatting language ✅ react-markdown - rendering Markdown in React ✅ @tailwindcss/typography - automatic styles (prose) ✅ react-syntax-highlighter - highlighting code blocks ✅ remark-gfm - GitHub Flavored Markdown (tables, tasks) ✅ rehype-sanitize - security (removes malicious HTML) ✅ Markdown Editor - textarea + live preview

See you there! 🚀

Go to CodeWorlds