-
-
Notifications
You must be signed in to change notification settings - Fork 916
Closed
Labels
👎 phase/noPost cannot or will not be acted onPost cannot or will not be acted on🙋 no/questionThis does not need any changesThis does not need any changes
Description
Initial checklist
- I read the support docs
- I read the contributing guide
- I agree to follow the code of conduct
- I searched issues and discussions and couldn’t find anything (or linked relevant results below)
Affected package
"tailwindcss": "^4.0.17" "react-markdown": "^10.1.0"
Steps to reproduce
Here is a component:
import { memo } from 'react';
import type { FC } from 'react';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import remarkGfm from 'remark-gfm';
import { cn } from '@/lib/utils';
type MessageFormatterProps = {
content: string;
className?: string;
};
/**
* MessageFormatter renders chat content with Markdown and code syntax highlighting
*
* Features:
* - Renders markdown with GitHub Flavored Markdown support
* - Syntax highlighting for code blocks with language detection
* - Styled inline code and text formatting
* - Responsive layout with proper spacing
*/
const MessageFormatter: FC<MessageFormatterProps> = ({ content, className }) => {
// Custom rendering components for markdown elements
const markdownComponents = {
// Code block handling with syntax highlighting
code({ className, children, ...props }: any) {
// Extract language from className (format: language-xxx)
const match = /language-(\w+)/.exec(className || '');
const language = match ? match[1] : '';
// Determine if we're dealing with a code block or inline code
const isCodeBlock = props.node?.position?.start.line !== props.node?.position?.end.line;
return isCodeBlock ? (
<SyntaxHighlighter
language={language || 'text'}
style={atomDark}
PreTag="div"
customStyle={{
borderRadius: '6px',
marginTop: '0.3em',
marginBottom: '0.3em',
fontSize: '0.9em',
}}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className="bg-muted px-1 py-0.5 rounded text-xs">
{children}
</code>
);
},
// Heading components with minimal margins
h1: ({ children }: any) => (
<h1 className="text-xl font-bold">{children}</h1>
),
h2: ({ children }: any) => (
<h2 className="text-lg font-bold">{children}</h2>
),
h3: ({ children }: any) => (
<h3 className="text-base font-bold">{children}</h3>
),
h4: ({ children }: any) => (
<h4 className="font-bold">{children}</h4>
),
// Link styling
a: ({ children, href }: any) => (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-primary underline hover:text-primary/80"
>
{children}
</a>
),
// List elements
ul: ({ children }: any) => <ul className="list-item ml-0 mr-0 mt-0 mb-0 ">{children}</ul>,
ol: ({ children }: any) => <ol className="list-decimal pl-2 my-0.5">{children}</ol>,
li: ({ children }: any) => <li className="my-0 mt-0 mb-0">{children}</li>,
// Paragraph
p: ({ children }: any) => <p className="my-0.5 mt-0 mb-0">{children}</p>,
// Tables
table: ({ children }: any) => (
<div className="my-0.5 overflow-x-auto">
<table className="min-w-[50%] border-collapse text-xs">{children}</table>
</div>
),
thead: ({ children }: any) => <thead className="bg-muted/50">{children}</thead>,
tr: ({ children }: any) => <tr className="border-b border-border">{children}</tr>,
th: ({ children }: any) => <th className="px-2 py-1 text-left font-medium">{children}</th>,
td: ({ children }: any) => <td className="px-2 py-1 border-r last:border-r-0 border-border">{children}</td>,
// Blockquote
blockquote: ({ children }: any) => (
<blockquote className="border-l-2 border-border pl-2 italic my-1 text-muted-foreground">
{children}
</blockquote>
),
// Horizontal rule
hr: () => <hr className="my-1 border-t border-border" />,
};
return (
<div className={cn("max-w-none", className)}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={markdownComponents}
>
{content}
</ReactMarkdown>
</div>
);
};
export default memo(MessageFormatter);
Actual behavior
This is actual rendered:

Expected behavior
This is the exact text from previous image, but pasted in Obsidian:

Runtime
No response
Package manager
bun
Operating system
macOS Sequoia 15.3.2
Build and bundle tools
Next.js
Metadata
Metadata
Assignees
Labels
👎 phase/noPost cannot or will not be acted onPost cannot or will not be acted on🙋 no/questionThis does not need any changesThis does not need any changes