Markdown
Render formatted markdown text as HTML with support for GFM, syntax highlighting, and sanitization
Markdown
Renders formatted markdown text as HTML with support for both synchronous and asynchronous rendering. Features GitHub Flavored Markdown (GFM), code syntax highlighting, tables, task lists, and optional HTML sanitization for user-generated content.
Installation
import { Markdown } from '@geckoui/geckoui';Basic Usage
Welcome to Markdown
This is a bold statement and this is italic.
Features
- GitHub Flavored Markdown (GFM)
- Tables, task lists, strikethrough
- Code syntax highlighting
- Math expressions
Code Example
function greet(name) {
console.log(`Hello, \${name}!`);
}
'use client';
import { Markdown } from '@geckoui/geckoui';
function Example() {
const content = `
## Welcome to Markdown
This is a **bold** statement and this is *italic*.
### Features
- GitHub Flavored Markdown (GFM)
- Tables, task lists, strikethrough
- Code syntax highlighting
### Code Example
\`\`\`javascript
function greet(name) {
console.log(\`Hello, \${name}!\`);
}
\`\`\`
`;
return <Markdown className="prose prose-sm max-w-none">{content}</Markdown>;
}Props API
| Prop | Type | Default | Description |
|---|---|---|---|
children | string | - | Markdown content to render (required) |
as | keyof JSX.IntrinsicElements | "div" | HTML element to wrap content |
async | boolean | false | Enable asynchronous rendering |
sanitize | boolean | true | Sanitize HTML to prevent XSS attacks |
renderPlaceholder | ReactNode | FC | - | Component to show during async loading |
renderError | ReactNode | FC<{message: string}> | <InputError> | Custom error component |
className | string | - | Additional CSS classes |
Supported Markdown Features
The component uses unified with the following plugins:
- remark-gfm: GitHub Flavored Markdown (tables, task lists, strikethrough)
- remark-math: Math expressions
- remark-directive: Custom directives
- remark-frontmatter: YAML frontmatter
- rehype-raw: HTML in markdown
- rehype-sanitize: HTML sanitization (when
sanitize={true}) - rehype-format: Pretty HTML output
Examples
Tables
GFM tables are fully supported:
Product Comparison
| Feature | Basic | Pro | Enterprise |
|---|---|---|---|
| Users | 5 | 50 | Unlimited |
| Storage | 10GB | 100GB | 1TB |
| Support | Priority | 24/7 Phone | |
| Price | $9/mo | $49/mo | Custom |
Notes
- All plans include SSL certificates
- Pro and Enterprise plans include API access
const content = `
## Product Comparison
| Feature | Basic | Pro | Enterprise |
|---------|-------|-----|------------|
| Users | 5 | 50 | Unlimited |
| Storage | 10GB | 100GB | 1TB |
| Support | Email | Priority | 24/7 Phone |
| Price | $9/mo | $49/mo | Custom |
`;
<Markdown className="prose">{content}</Markdown>Task Lists
Interactive checkbox lists:
Project Checklist
Phase 1: Design
- Wireframes
- Design system
- User flows
Phase 2: Development
- Backend API
- Frontend components
- Integration tests
- E2E tests
Phase 3: Launch
- Beta release
- Marketing campaign
- Production deployment
const content = `
## Project Checklist
### Phase 1: Design
- [x] Wireframes
- [x] Design system
- [x] User flows
### Phase 2: Development
- [x] Backend API
- [x] Frontend components
- [ ] Integration tests
- [ ] E2E tests
`;
<Markdown className="prose">{content}</Markdown>When to use async:
- Processing large markdown files
- Preventing UI blocking during rendering
Behavior:
- Shows
renderPlaceholderwhile processing - Updates when
childrenchanges - Handles errors gracefully
Error Handling
Customize error display:
Valid Content
This is properly formatted markdown.
- List item 1
- List item 2
import { Markdown, Alert } from '@geckoui/geckoui';
<Markdown
renderError={({ message }) => <Alert variant="error">Error: {message}</Alert>}
className="prose"
>
{content}
</Markdown>Default Behavior:
- Without
renderError: Shows<InputError>with error message - With
renderError: Renders your custom component - Error component receives
messageprop
Sanitized User Content
Protect against XSS attacks in user-generated content:
Without Sanitization (Dangerous)
User Generated Content
This content includes potentially dangerous HTML:
Safe Content
This markdown is safe and will render correctly.
- Item 1
- Item 2
With Sanitization (Safe)
User Generated Content
This content includes potentially dangerous HTML:
Safe Content
This markdown is safe and will render correctly.
- Item 1
- Item 2
<Markdown sanitize className="prose">
{userGeneratedMarkdown}
</Markdown>What gets sanitized:
<script>tags removedonclickand other event handlers removedjavascript:URLs blocked- Potentially dangerous attributes stripped
- Markdown formatting preserved
Important: Always use sanitize={true} for user-generated content!
Custom Wrapper Element
Use semantic HTML elements:
Article Content
This is rendered as an article element instead of a div.
Benefits
- Better semantic HTML
- Improved accessibility
- SEO advantages
Use the
asprop to customize the wrapper element.
<Markdown as="article" className="prose">
{content}
</Markdown>Performance Considerations
Sync vs Async
Synchronous (default):
- Blocks rendering until complete
- Use for small/medium content
- No loading state needed
- Simpler code
Asynchronous:
- Non-blocking rendering
- Use for large content (>10KB)
- Requires loading state
- Better perceived performance
// Small content: use sync (default)
<Markdown>{smallContent}</Markdown>
// Large content: use async
<Markdown async renderPlaceholder={<Spinner />}>
{largeContent}
</Markdown>Security Best Practices
-
Always sanitize user content:
<Markdown sanitize>{userContent}</Markdown> -
Validate content sources:
// ✅ Safe: Your own content <Markdown>{yourContent}</Markdown> // ❌ Unsafe: Untrusted user content without sanitization <Markdown sanitize={false}>{untrustedContent}</Markdown> // ✅ Safe: Sanitized user content <Markdown sanitize>{untrustedContent}</Markdown> -
Content Security Policy: Add CSP headers to prevent script injection
-
Rate limiting: Limit how much content users can submit
Accessibility
- Semantic HTML structure (headings, lists, tables)
- Proper heading hierarchy (h1, h2, h3...)
- Alt text for images (if included in markdown)
- Table headers for screen readers
- Focus management for interactive elements
TypeScript
Basic Usage
import { Markdown } from '@geckoui/geckoui';
const content: string = '## Hello';
<Markdown>{content}</Markdown>With Custom Element
import type { MarkdownProps } from '@geckoui/geckoui';
const MyMarkdown: React.FC<MarkdownProps<'article'>> = (props) => {
return <Markdown as="article" {...props} />;
};With Error Handler
const errorHandler: React.FC<{ message: string }> = ({ message }) => (
<div className="error">{message}</div>
);
<Markdown renderError={errorHandler}>{content}</Markdown>Styling
The component uses the class name GeckoUIMarkdown. You can target it in your CSS to apply custom styles:
.GeckoUIMarkdown {
/* Your custom styles */
}Large content performance
For very large markdown files (>100KB):
- Use
async={true} - Consider code splitting
- Implement pagination
- Use virtual scrolling
Related Components
- MermaidDiagram - Render diagrams from markdown
- Alert - Error handling UI
Related Hooks
- useMarkdown - Underlying hook for custom implementations