Markdown Response
Preview: Rendered
Renders model output as Markdown (GFM tables, task lists, code). Safe by default: raw HTML in the text is not rendered, so model output can't inject markup.
Import
import { MarkdownResponse } from '@marbleui/ui'Props
<MarkdownResponse>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | string | — | |
| className | string | — | |
| isStreaming | boolean | — | Show a blinking caret at the end while tokens stream in. |
| size | 'sm' | 'md' | 'sm' |
Usage notes
Renders model output as Markdown: GFM tables, task lists, links and fenced code. Use it as the body of an assistant ChatMessage. For trusted content you render yourself, wrap it in Prose.
<ChatMessage role="assistant" name="Acme AI" actions={<MessageActions text={reply} />}>
<MarkdownResponse isStreaming={status === 'streaming'}>{reply}</MarkdownResponse>
</ChatMessage>
childrenmust be a string. Pass the whole text so far on each token;isStreamingadds a blinking caret after the last block.sizeissm(default) ormd.- Raw HTML in the text shows as literal text, so model output can’t inject markup. Links open in a new tab.
- Fenced code becomes a
CodeBlockwith a copy button, and line numbers on longer blocks. Task-list checkboxes are read-only and named “Done” or “Not done”. - Because it only takes a string,
Citations can’t go inside it; list sources after it withSources.
Example source · show· hide
import { useEffect, useState } from 'react'
import { Button } from '../button'
import { MarkdownResponse } from './markdown-response'
const answer = `Here's how to theme **Marble UI** per section:
1. Wrap the area in an element with \`data-theme="soft"\`
2. Add the \`dark\` class for dark mode
3. Overlays inherit it via the portal container
| Preset | Radius | Accent |
| --- | --- | --- |
| Minimal | 8px | Ink |
| Soft | 14px | Violet |
\`\`\`tsx
<div data-theme="soft" className="dark">
<Button>Themed</Button>
</div>
\`\`\`
> Tip: chart colors stay the same across presets on purpose.
- [x] Tokens
- [ ] Your brand preset`
function Streaming() {
const [n, setN] = useState(0)
useEffect(() => {
if (n >= answer.length) return
const t = setTimeout(() => setN((v) => Math.min(answer.length, v + 6)), 30)
return () => clearTimeout(t)
}, [n])
return (
<div className="flex w-[34rem] flex-col gap-3">
<MarkdownResponse isStreaming={n < answer.length}>{answer.slice(0, n)}</MarkdownResponse>
<Button size="sm" variant="outline" className="self-start" onPress={() => setN(0)}>Replay</Button>
</div>
)
}
export const styles = {
Rendered: () => <div className="w-[34rem]"><MarkdownResponse>{answer}</MarkdownResponse></div>,
Streaming,
}Source: packages/ui/src/markdown-response/markdown-response.tsx
Catalog
- Category
- ai-agents
- Priority
- Pro
- Primitive
- custom