Quête

Back to Blog

Hello World!

June 5, 2025
Joel
Updated 6/5/2025

alt text

Using the ReactMarkdown, RemarGFM and Snytax highlighters I created a simple Blog posting util for markdown

The library is pretty straight forward and uses nextjs routes to post to a postgres backend.

This keeps it simple, so I can keep the same stack and not have to spin up an overweight service that I don't need. The problem is of course it isn't loaded with the SEO features you get with proper blog/editors. But I'd rather just have a simple way to do it in nextjs.

The acutal code:


  • RemarkGFM: Gives you the Github Styled Markdown features. Strikethrough, lines etc
    • Prism SyntaxHighlighter: Highlighting with multiple themes

import ReactMarkdown from "react-markdown"
import remarkGfm from "remark-gfm"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter

The Formatting Toolbar

The toolbar is pretty simple and straight forward to setup

const toolbarButtons = [ { icon: <Bold size={16} />, action: () => insertMarkdown("**", "**"), tooltip: "Bold", }, { icon: <Italic size={16} />, action: () => insertMarkdown("*", "*"), tooltip: "Italic", }, { icon: <Strikethrough size={16} />, action: () => insertMarkdown("~~", "~~"), tooltip: "Strikethrough", }, { icon: <Code size={16} />, action: () => insertMarkdown("`", "`"), tooltip: "Inline Code", }, { icon: <Link size={16} />, action: () => insertMarkdown("[", "](url)"), tooltip: "Link", }, { icon: <List size={16} />, action: () => insertMarkdown("- ", ""), tooltip: "Bullet List", }, { icon: <Hash size={16} />, action: () => insertMarkdown("## ", ""), tooltip: "Heading", }, ]

Smart Text Insertion


The insertMarkdown function handles intelligent text wrapping and cursor positioning:

const insertMarkdown = (before, after) => { const textarea = textareaRef.current const start = textarea.selectionStart const end = textarea.selectionEnd const selectedText = content.substring(start, end) // If text is selected, wrap it if (selectedText) { const newText = content.substring(0, start) + before + selectedText + after + content.substring(end) setContent(newText) // Set cursor position after the insertion setTimeout(() => { textarea.focus() textarea.setSelectionRange( start + before.length, end + before.length ) }, 0) } else { // No selection, just insert the markdown syntax const newText = content.substring(0, start) + before + after + content.substring(start) setContent(newText) // Position cursor between the markdown syntax setTimeout(() => { textarea.focus() textarea.setSelectionRange( start + before.length, start + before.length ) }, 0) } }

And most importantly:

For code blocks:

const CodeBlock = ({ className, children, ...props }) => { const match = /language-(\w+)/.exec(className || '') const language = match ? match[1] : 'text' return ( <SyntaxHighlighter style={oneDark} language={language} PreTag="div" className="rounded-lg" showLineNumbers={true} {...props} > {String(children).replace(/\n$/, '')} </SyntaxHighlighter> ) }

alt text