mirror of https://github.com/usememos/memos.git
3.3 KiB
3.3 KiB
Markdown Components
Modern, type-safe React components for rendering markdown content via react-markdown.
Architecture
Component-Based Rendering
Following patterns from popular AI chat apps (ChatGPT, Claude, Perplexity), we use React components instead of CSS selectors for markdown rendering. This provides:
- Type Safety: Full TypeScript support with proper prop types
- Maintainability: Components are easier to test, modify, and understand
- Performance: No CSS specificity conflicts, cleaner DOM
- Modularity: Each element is independently styled and documented
Type System
All components extend ReactMarkdownProps which includes the AST node prop passed by react-markdown. This is explicitly destructured as node: _node to:
- Filter it from DOM props (avoids
node="[object Object]"in HTML) - Keep it available for advanced use cases (e.g., detecting task lists)
- Maintain type safety without
as anycasts
GFM Task Lists
Task lists (from remark-gfm) are handled by:
- Detection:
contains-task-listandtask-list-itemclasses from remark-gfm - Styling: Tailwind utilities with arbitrary variants for nested elements
- Checkboxes: Custom
TaskListItemcomponent with Radix UI checkbox - Interactivity: Updates memo content via
toggleTaskAtIndexutility
Component Patterns
Each component follows this structure:
import { cn } from "@/lib/utils";
import type { ReactMarkdownProps } from "./types";
interface ComponentProps extends React.HTMLAttributes<HTMLElement>, ReactMarkdownProps {
children?: React.ReactNode;
// component-specific props
}
/**
* JSDoc description
*/
export const Component = ({ children, className, node: _node, ...props }: ComponentProps) => {
return (
<element className={cn("base-classes", className)} {...props}>
{children}
</element>
);
};
Components
| Component | Element | Purpose |
|---|---|---|
Heading |
h1-h6 | Semantic headings with level-based styling |
Paragraph |
p | Compact paragraphs with consistent spacing |
Link |
a | External links with security attributes |
List |
ul/ol | Regular and GFM task lists |
ListItem |
li | List items with task checkbox support |
Blockquote |
blockquote | Quotes with left border accent |
InlineCode |
code | Inline code with background |
Image |
img | Responsive images with rounded corners |
HorizontalRule |
hr | Section separators |
Styling Approach
- Tailwind CSS: All styling uses Tailwind utilities
- Design Tokens: Colors use CSS variables (e.g.,
--primary,--muted-foreground) - Responsive: Max-width constraints, responsive images
- Accessibility: Semantic HTML, proper ARIA attributes via Radix UI
Integration
Components are mapped to HTML elements in MemoContent/index.tsx:
<ReactMarkdown
components={{
h1: ({ children }) => <Heading level={1}>{children}</Heading>,
p: ({ children, ...props }) => <Paragraph {...props}>{children}</Paragraph>,
// ... more mappings
}}
>
{content}
</ReactMarkdown>
Future Enhancements
- Syntax highlighting themes for code blocks
- Table sorting/filtering interactions
- Image lightbox/zoom functionality
- Collapsible sections for long content
- Copy button for code blocks