Skip to content

Commit 8fd4f4b

Browse files
authored
feat: add custom markdown example (#194)
1 parent b092d5e commit 8fd4f4b

File tree

2 files changed

+204
-1
lines changed

2 files changed

+204
-1
lines changed

.changeset/curly-buses-kick.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
"@llamaindex/chat-ui": patch
2+
'@llamaindex/chat-ui': patch
33
---
44

55
Expose ReactMarkdown `components` prop
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
'use client'
2+
3+
import { Markdown } from '@llamaindex/chat-ui/widgets'
4+
5+
const sampleMarkdown = `# Custom Markdown Components Example
6+
7+
This example demonstrates how to customize the **Markdown** component using the new \`components\` prop.
8+
9+
## Custom Headings
10+
### This is a custom H3 heading
11+
#### And this is a custom H4 heading
12+
13+
## Custom Paragraphs
14+
This paragraph will be rendered with custom styling. The new components prop allows you to override any markdown element with your own React components.
15+
16+
You can customize:
17+
- **Headings** (h1, h2, h3, h4, h5, h6)
18+
- **Paragraphs** and text formatting
19+
- **Links** and navigation
20+
- **Lists** (both ordered and unordered)
21+
- **Code blocks** and inline code
22+
- **Images** and media
23+
- **Tables** and data display
24+
- **Blockquotes** and emphasis
25+
26+
## Custom Links
27+
Check out this [custom styled link](https://llamaindex.ai) that opens with special behavior.
28+
29+
## Custom Code Examples
30+
Here's some inline \`custom code\` and a code block:
31+
32+
\`\`\`javascript
33+
// This code block uses the default renderer
34+
function defaultRenderer() {
35+
return "Default code rendering";
36+
}
37+
\`\`\`
38+
39+
\`\`\`mermaid
40+
graph TD
41+
A[Custom Components] --> B[Better UX]
42+
A --> C[Consistent Design]
43+
B --> D[Happy Users]
44+
C --> D
45+
\`\`\`
46+
47+
## Custom Lists
48+
- First custom list item
49+
- Second custom list item with **bold text**
50+
- Third item with [a link](https://example.com)
51+
52+
1. Numbered custom item
53+
2. Another numbered item
54+
3. Final numbered item
55+
56+
## Custom Blockquotes
57+
> This is a custom blockquote that can have special styling and behavior.
58+
>
59+
> It can span multiple lines and include **formatting**.
60+
61+
---
62+
63+
*This entire markdown content is rendered with custom components!*
64+
65+
## Custom Language Renderer
66+
This example also shows custom language renderers - notice how the mermaid diagram above gets special treatment!
67+
`
68+
69+
// Custom component implementations
70+
const customComponents = {
71+
// Custom heading components with special styling
72+
h1: ({ children }: { children: React.ReactNode }) => (
73+
<h1 className="mb-4 border-b-2 border-blue-200 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text pb-2 text-4xl font-bold text-transparent">
74+
🚀 {children}
75+
</h1>
76+
),
77+
78+
h2: ({ children }: { children: React.ReactNode }) => (
79+
<h2 className="mb-3 mt-6 flex items-center gap-2 text-3xl font-semibold text-blue-700">
80+
<span className="h-6 w-2 rounded bg-blue-500" />
81+
{children}
82+
</h2>
83+
),
84+
85+
h3: ({ children }: { children: React.ReactNode }) => (
86+
<h3 className="mb-3 mt-5 flex items-center gap-2 text-2xl font-medium text-purple-600">
87+
<span className="h-5 w-1.5 rounded bg-purple-400" />
88+
{children}
89+
</h3>
90+
),
91+
92+
h4: ({ children }: { children: React.ReactNode }) => (
93+
<h4 className="mb-2 mt-4 flex items-center gap-2 text-xl font-medium text-green-600">
94+
<span className="h-4 w-1 rounded bg-green-400" />
95+
{children}
96+
</h4>
97+
),
98+
99+
// Custom paragraph with special styling
100+
p: ({ children }: { children: React.ReactNode }) => (
101+
<div className="mb-4 rounded-lg border-l-4 border-blue-200 bg-gray-50 p-4 leading-relaxed text-gray-700 dark:border-blue-700 dark:bg-gray-800/50 dark:text-gray-300">
102+
{children}
103+
</div>
104+
),
105+
106+
// Custom link component with hover effects
107+
a: ({ href, children }: { href?: string; children: React.ReactNode }) => (
108+
<a
109+
href={href}
110+
target="_blank"
111+
rel="noopener noreferrer"
112+
className="inline-flex items-center gap-1 rounded px-1 py-0.5 font-medium text-blue-600 underline decoration-blue-300 decoration-2 transition-all duration-200 hover:bg-blue-50 hover:text-blue-800 hover:decoration-blue-500 dark:text-blue-400 dark:hover:bg-blue-900/20 dark:hover:text-blue-300"
113+
onClick={() => {
114+
console.log('Custom link clicked:', href)
115+
}}
116+
>
117+
{children}
118+
<span className="text-xs">🔗</span>
119+
</a>
120+
),
121+
122+
// Custom list components
123+
ul: ({ children }: { children: React.ReactNode }) => (
124+
<ul className="mb-4 space-y-2 rounded-lg border border-green-200 bg-gradient-to-r from-green-50 to-blue-50 p-4 dark:border-green-700 dark:from-green-900/10 dark:to-blue-900/10">
125+
{children}
126+
</ul>
127+
),
128+
129+
ol: ({ children }: { children: React.ReactNode }) => (
130+
<ol className="mb-4 space-y-2 rounded-lg border border-purple-200 bg-gradient-to-r from-purple-50 to-pink-50 p-4 dark:border-purple-700 dark:from-purple-900/10 dark:to-pink-900/10">
131+
{children}
132+
</ol>
133+
),
134+
135+
li: ({ children }: { children: React.ReactNode }) => (
136+
<li className="flex items-start gap-2">
137+
<span className="mt-1 font-bold text-blue-500"></span>
138+
<span className="text-gray-700 dark:text-gray-300">{children}</span>
139+
</li>
140+
),
141+
142+
// Custom blockquote
143+
blockquote: ({ children }: { children: React.ReactNode }) => (
144+
<blockquote className="mb-4 rounded-r-lg border-l-4 border-yellow-400 bg-gradient-to-r from-yellow-50 to-orange-50 p-4 italic dark:from-yellow-900/10 dark:to-orange-900/10">
145+
<div className="flex items-start gap-3">
146+
<span className="text-2xl text-yellow-500">💡</span>
147+
<div className="text-gray-700 dark:text-gray-300">{children}</div>
148+
</div>
149+
</blockquote>
150+
),
151+
152+
// Custom code block (inline)
153+
code: ({
154+
inline,
155+
children,
156+
}: {
157+
inline?: boolean
158+
children: React.ReactNode
159+
}) => {
160+
if (inline) {
161+
return (
162+
<code className="rounded border border-purple-200 bg-purple-100 px-2 py-1 font-mono text-sm text-purple-800 dark:border-purple-700 dark:bg-purple-900/30 dark:text-purple-300">
163+
{children}
164+
</code>
165+
)
166+
}
167+
// For block code, let the default handler take over
168+
return <code>{children}</code>
169+
},
170+
171+
// Custom horizontal rule
172+
hr: () => (
173+
<div className="my-8 flex items-center gap-4">
174+
<div className="h-0.5 flex-1 bg-gradient-to-r from-transparent via-blue-300 to-transparent" />
175+
<span className="text-xl text-blue-500"></span>
176+
<div className="h-0.5 flex-1 bg-gradient-to-r from-transparent via-blue-300 to-transparent" />
177+
</div>
178+
),
179+
180+
// Custom strong/bold text
181+
strong: ({ children }: { children: React.ReactNode }) => (
182+
<strong className="rounded bg-blue-50 px-1 py-0.5 font-bold text-blue-700 dark:bg-blue-900/20 dark:text-blue-300">
183+
{children}
184+
</strong>
185+
),
186+
187+
// Custom emphasis/italic text
188+
em: ({ children }: { children: React.ReactNode }) => (
189+
<em className="rounded bg-purple-50 px-1 py-0.5 italic text-purple-600 dark:bg-purple-900/20 dark:text-purple-400">
190+
{children}
191+
</em>
192+
),
193+
}
194+
195+
export default function CustomMarkdownPage() {
196+
return (
197+
<div className="container mx-auto max-w-4xl p-6">
198+
<div className="rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900">
199+
<Markdown content={sampleMarkdown} components={customComponents} />
200+
</div>
201+
</div>
202+
)
203+
}

0 commit comments

Comments
 (0)