- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
TextPart markdown
TextPart in the React, Vue, and Solid UI packages now renders with TanStack Markdown. Pass extensions and highlighter. remarkPlugins, rehypePlugins, and disableDefaultPlugins are removed.
This page is only for apps that import the TextPart component. createChatHook does not use it unless you pass it as partsComponents.text.
Upgrade#
- Find each TextPart in your code that has a plugin prop or a Solid components prop.
- Replace each prop with the prop map below.
- If you want colored code fences, follow Syntax highlighting.
- Read Silent changes. Default <TextPart content={...} /> compiles, but some output looks different.
Prop map#
| Old prop | New prop |
|---|---|
| remarkPlugins | extensions (MarkdownExtension[] from @tanstack/markdown) |
| rehypePlugins | extensions or highlighter |
| disableDefaultPlugins | Removed. The streaming extension is always on. |
| Solid components | Removed |
| 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. Remove the plugin:
// Before
import { TextPart } from '@tanstack/ai-react/ui'
import remarkCjkFriendly from 'remark-cjk-friendly'
<TextPart content={content} remarkPlugins={[remarkCjkFriendly]} />// After
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 removed the hljs-* classes, so fenced code already looked plain.
To get colors, pass a TanStack Highlight callback. For the full steps, see Highlight markdown code.
// Before
<TextPart content={content} />// After
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"
/>
)
}Other remark or rehype plugins#
A unified plugin has no drop-in replacement. Write the behavior again as a TanStack Markdown extension, or do it outside TextPart.
You cannot turn off the streaming extension.
React components#
React still accepts components, but the type is now MarkdownComponents, not the Components type of react-markdown. TanStack Markdown passes only intrinsic HTML props.
A common override still type-checks, but renders wrong, because inline is always undefined:
// Before: compiles, but every code element renders as a block
<TextPart
content={content}
components={{
code: ({ inline, children }) =>
inline ? <code>{children}</code> : <pre>{children}</pre>,
}}
/>// After
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" />,
}}
/>
)
}To tell a fence from inline code, read className (for example language-ts). Do not read inline or node.
Silent changes#
These changes happen with a default <TextPart content={...} />. You get 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 removed) | Plain, with tm-code / language-* |
| CJK bold **…。**次 | Failed without a plugin | Works |
Tables, lists, strikethrough, and fenced code still render.
These things do not change:
- createChatHook apps that render {part.content} themselves.
- The import path: still @tanstack/ai-react/ui (or the Vue or Solid /ui subpath).
- The TextPart data type on messages ({ type: 'text', content }). That is a type, not this component.
Done#
Your type checker passes, and your replies render with TanStack Markdown. To add colored code fences, follow Highlight markdown code.