Persistence (Advanced)
- Overview
- Quick Start
- Providers
- Harnesses
- Harness Auth
- Workspace
- Tools
- Policy
- Lifecycle & Snapshots
- Portable Snapshots
- Keep Files After Reload
- Save a Named Version
- Branch From a Version
- Send a Frozen File
- Let the Agent Save and Fork
- Pick Which Files to Keep
- What a Snapshot Stores
- Instance Durability
- Durable Runs
- Events
Sandboxes (Advanced)
TextPart markdown
TL;DR: This is a breaking change. TextPart no longer accepts remarkPlugins, rehypePlugins, or disableDefaultPlugins. Pass extensions and highlighter instead. Default <TextPart content={...} /> still type-checks. Bare URLs stay plain text. Raw HTML in the model is escaped.
TextPart from @tanstack/ai-react/ui, @tanstack/ai-vue/ui, and @tanstack/ai-solid/ui now renders with TanStack Markdown.
This page is only for people who already import that component. createChatHook does not use it unless you pass it as partsComponents.text. Deprecated ChatMessage still prints plain text.
Who this hits#
- You passed remarkPlugins, rehypePlugins, or disableDefaultPlugins. Type-check fails.
- You passed Solid components. Type-check fails. React components stays, with a new type.
- You used default TextPart with only content. It compiles. Output can look different (see Silent changes).
Prop map#
| Old prop | New prop |
|---|---|
| remarkPlugins | extensions (MarkdownExtension[] from @tanstack/markdown) |
| rehypePlugins | extensions or highlighter |
| disableDefaultPlugins | gone. The streaming extension is always on |
| Solid components | gone |
| React components | components (MarkdownComponents: a tag-name map with normal HTML props) |
A unified plugin such as remark-gfm or remark-cjk-friendly is not a TanStack Markdown extension. You cannot pass it through.
Replace plugin props#
CJK bold#
TanStack Markdown parses CJK bold with no plugin.
import { TextPart } from '@tanstack/ai-react/ui'
import remarkCjkFriendly from 'remark-cjk-friendly'
<TextPart content={content} remarkPlugins={[remarkCjkFriendly]} />import { TextPart } from '@tanstack/ai-react/ui'
export function Reply({ content }: { content: string }) {
return <TextPart content={content} />
}Syntax highlighting#
The old stack ran rehype-highlight, then rehype-sanitize stripped the hljs-* classes. Fenced code already looked plain.
To get colors now, pass a TanStack Highlight callback. Full steps: Highlight markdown code.
<TextPart content={content} />import { TextPart } from '@tanstack/ai-react/ui'
import { highlightMarkdownCode } from './markdown-highlighter'
export function Reply({ content }: { content: string }) {
return (
<TextPart
content={content}
highlighter={highlightMarkdownCode}
className="markdown-renderer"
/>
)
}Extra remark or rehype plugins#
There is no drop-in for a unified plugin. Rewrite the behavior as a TanStack Markdown extension, or handle it outside TextPart.
disableDefaultPlugins is gone. You cannot turn off the streaming extension.
React components#
React still accepts components. The type is no longer react-markdown Components. TanStack Markdown passes intrinsic HTML props only.
A common override still type-checks, then mis-renders. inline is always undefined.
<TextPart
content={content}
components={{
code: ({ inline, children }) =>
inline ? <code>{children}</code> : <pre>{children}</pre>,
}}
/>import { TextPart } from '@tanstack/ai-react/ui'
export function Reply({ content }: { content: string }) {
return (
<TextPart
content={content}
components={{
a: (props) => <a {...props} target="_blank" rel="noreferrer" />,
}}
/>
)
}Branch on className (for example language-ts) if you need fence vs inline. Do not read inline or node.
Silent changes#
These happen with default <TextPart content={...} />. There is no type error.
| Input | Before | After |
|---|---|---|
| Bare URL https://example.com | Auto-linked | Plain text |
| Raw HTML such as <br> or <img> | Sanitized, then rendered | Escaped text |
| Task list | contains-task-list / task-list-item | Checkbox on a plain <li> |
| Fenced code | Plain (highlight classes stripped) | Plain, with tm-code / language-* |
| CJK bold **…。**次 | Failed without a plugin | Works |
Tables, lists, strikethrough, and fenced code still render.
What does not change#
- createChatHook apps that render {part.content} themselves.
- Deprecated ChatMessage text output (plain text).
- Import path: still @tanstack/ai-react/ui (or Vue / Solid /ui).
- The TextPart data type on messages ({ type: 'text', content }). That is not this component.
When the type error is gone and you want colored fences, follow Highlight markdown code.