Markdown Renderer
AI & ChatMarkdown-to-HTML content renderer.
Preview
Hello World
This is bold and italic text.
const greeting = "Hello!";
console.log(greeting);Usage
example.jsx
import { MarkdownRenderer } from "@/components/ui/markdown-renderer";
export default function Example() {
return <MarkdownRenderer />;
}Source Code
Copy this file into components/ui/markdown-renderer.jsx in your project.
markdown-renderer.jsx
import { forwardRef } from "react";
import { cn } from "@/lib/utils";
function renderInline(text) {
return text
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/\*(.*?)\*/g, "<em>$1</em>")
.replace(/`(.*?)`/g, '<code class="rounded bg-muted px-1 py-0.5 font-mono text-sm">$1</code>')
.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" class="text-primary underline">$1</a>');
}
const MarkdownRenderer = forwardRef(({ className, content = "", ...props }, ref) => {
const lines = content.split("\n");
const html = [];
let inCode = false, codeBuf = [], codeLang = "";
for (const line of lines) {
if (line.startsWith("```")) {
if (!inCode) { inCode = true; codeLang = line.slice(3); codeBuf = []; }
else { html.push(`<pre class="overflow-x-auto rounded-lg bg-muted p-4 font-mono text-sm my-2"><code>${codeBuf.join("\n")}</code></pre>`); inCode = false; }
continue;
}
if (inCode) { codeBuf.push(line.replace(/</g, "<")); continue; }
if (line.startsWith("### ")) html.push(`<h3 class="mt-4 mb-2 text-lg font-semibold">${line.slice(4)}</h3>`);
else if (line.startsWith("## ")) html.push(`<h2 class="mt-4 mb-2 text-xl font-semibold">${line.slice(3)}</h2>`);
else if (line.startsWith("# ")) html.push(`<h1 class="mt-4 mb-2 text-2xl font-bold">${line.slice(2)}</h1>`);
else if (line.startsWith("- ") || line.startsWith("* ")) html.push(`<li class="ml-4 list-disc">${renderInline(line.slice(2))}</li>`);
else if (/^\d+\.\s/.test(line)) html.push(`<li class="ml-4 list-decimal">${renderInline(line.replace(/^\d+\.\s/, ""))}</li>`);
else if (line.startsWith("> ")) html.push(`<blockquote class="border-l-4 border-muted pl-4 italic text-muted-foreground my-2">${renderInline(line.slice(2))}</blockquote>`);
else if (line.trim() === "") html.push("<br/>");
else html.push(`<p class="my-1">${renderInline(line)}</p>`);
}
return <div ref={ref} className={cn("prose prose-sm max-w-none dark:prose-invert", className)} dangerouslySetInnerHTML={{ __html: html.join("") }} {...props} />;
});
MarkdownRenderer.displayName = "MarkdownRenderer";
export { MarkdownRenderer };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge