
X Components
- 56 installs
- 4.7k repo stars
- Updated August 4, 2026
- ant-design/x
x-components is a Claude Code skill covering the @ant-design/x React component library for building AI chat UIs, including Bubble, Sender, Conversations, ThoughtChain, and Actions.
About
This skill covers the UI components in the @ant-design/x React library for building AI chat interfaces. A developer uses it to choose components like Bubble, Sender, Conversations, ThoughtChain, and Actions for each part of a chat screen and compose them into a page. It documents API usage, composition patterns, and common anti-patterns such as mapping Bubble manually instead of using Bubble.List.
- Covers all @ant-design/x React chat components: Bubble, Sender, Conversations, ThoughtChain, and more
- Maps each RICH interaction stage to the right component
- Includes a minimal full-page chat example and anti-pattern rules
X Components by the numbers
- 56 all-time installs (skills.sh)
- Ranked #1,245 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
x-components capabilities & compatibility
- Capabilities
- ai chat ui · component selection · ui composition
- Use cases
- frontend · ui design
What x-components says it does
This skill covers all UI components in `@ant-design/x`** — the React component library for building AI-driven chat interfaces based on the RICH interaction paradigm.
**`Bubble.List` not `Bubble` in loops** — `Bubble.List` handles scroll anchoring, auto-scroll, and role-based layout; mapping `Bubble` manually loses these.
npx skills add https://github.com/ant-design/x --skill x-componentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 56 |
|---|---|
| repo stars | ★ 4.7k |
| Last updated | August 4, 2026 |
| Repository | ant-design/x ↗ |
What it does
Select and compose @ant-design/x React components to build an AI chat interface.
Who is it for?
Choosing and composing @ant-design/x React components for an AI chat interface
Skip if: Data flow, streaming, or markdown rendering, which are handled by the x-request, use-x-chat, and x-markdown skills
When should I use this skill?
You are building or reviewing an AI chat UI with @ant-design/x components
What you get
A correctly composed @ant-design/x chat UI wrapped in XProvider
- Composed @ant-design/x chat UI page
By the numbers
- Documents 18+ named components across six RICH interaction stages
Files
🎯 Skill Positioning
This skill covers all UI components in `@ant-design/x` — the React component library for building AI-driven chat interfaces based on the RICH interaction paradigm.
It covers component selection, API usage, composition patterns, and common anti-patterns.
Prerequisite: This skill handles UI only. For data flow and streaming, seeuse-x-chat,x-chat-provider,x-requestskills.
Table of Contents
- 📦 Package Overview
- 🗂️ Component Groups
- 🚀 Quick Start Decision Guide
- 🛠 Recommended Workflow
- 🚨 Development Rules
- 🤝 Skill Collaboration
- 🔗 Reference Resources
📦 Package Overview
| Package | Responsibility |
|---|---|
@ant-design/x | All UI components in this skill |
@ant-design/x-sdk | Data providers, request, streaming state — not covered here |
@ant-design/x-markdown | Markdown rendering inside Bubble — see x-markdown skill |
npm install @ant-design/x@ant-design/xextendsantd. If you useConfigProvider, replace it withXProvider.
🗂️ Component Groups
Based on the RICH interaction paradigm:
| Stage | Components |
|---|---|
| General | Bubble, Bubble.List, Conversations, Notification |
| Wake | Welcome, Prompts |
| Express | Sender, Attachments, Suggestion |
| Confirmation | Think, ThoughtChain |
| Feedback | Actions, FileCard, Sources, CodeHighlighter, Mermaid, Folder |
| Global | XProvider |
🚀 Quick Start Decision Guide
| If you need to... | Read first |
|---|---|
| Render a chat message bubble | COMPONENTS.md → Bubble |
| Build a chat input box | COMPONENTS.md → Sender |
| List and switch conversations | COMPONENTS.md → Conversations |
| Show AI thinking process | COMPONENTS.md → ThoughtChain / Think |
| Add action buttons below a message | COMPONENTS.md → Actions |
| Build a welcome / onboarding screen | COMPONENTS.md → Welcome + Prompts |
| Show file attachments in input | COMPONENTS.md → Attachments |
| Show source citations | COMPONENTS.md → Sources |
| Add quick command suggestions | COMPONENTS.md → Suggestion |
| Display a hierarchical file/folder tree | COMPONENTS.md → Folder |
| Wire a complete chat page | PATTERNS.md |
| Look up a specific prop | API.md |
🛠 Recommended Workflow
1. Pick components from COMPONENTS.md for each interaction stage. 2. Use PATTERNS.md to understand how components compose into full pages. 3. Wrap the app root with XProvider (replaces antd's ConfigProvider) for locale, theme, and shortcut keys. 4. Use API.md for precise prop names — do not guess them.
Minimal Full-Page Example
import { XProvider, Welcome, Prompts, Bubble, Sender } from '@ant-design/x';
export default () => (
<XProvider>
<Welcome title="Hello!" description="How can I help you?" />
<Prompts
items={[{ key: '1', label: 'What can you do?' }]}
onItemClick={(info) => console.log(info.data.label)}
/>
<Bubble.List items={[{ key: '1', content: 'Hello World', placement: 'end' }]} />
<Sender onSubmit={(msg) => console.log(msg)} />
</XProvider>
);🚨 Development Rules
- Always use `XProvider` at the app root — it supersedes
antd'sConfigProviderand enables locale, direction, and x-specific shortcut keys. - `Bubble.List` not `Bubble` in loops —
Bubble.Listhandles scroll anchoring, auto-scroll, and role-based layout; mappingBubblemanually loses these. - Keep `components` prop stable in
BubbleandBubble.List— inline object creation causes re-renders and resets typing animations. - Set `streaming={true}` during stream, `streaming={false}` on final chunk — leaving it
truepermanently breaks the done state. - `ThoughtChain` vs `Think`: use
ThoughtChainfor multi-step tool/agent call chains; useThinkfor a collapsible single-block reasoning display. - `Actions.Copy`, `Actions.Feedback`, `Actions.Audio` are preset sub-components — prefer them over building custom equivalents.
- Sender `onSubmit` vs `onChange`:
onSubmitfires on send button or Enter key;onChangefires on every keystroke — do not conflate them. - Never render `Mermaid` or `CodeHighlighter` inside a `Bubble` `content` string — use
contentRenderor thecomponentsmap instead.
🤝 Skill Collaboration
| Scenario | Skill combination |
|---|---|
| Full AI chat app | x-chat-provider → x-request → use-x-chat → x-components → x-markdown |
| Just building UI structure | x-components only |
| Markdown in bubble replies | x-components + x-markdown |
| Streaming data flow only | use-x-chat + x-request |
🔗 Reference Resources
- COMPONENTS.md — Component-by-component guide with usage, key props, and examples
- PATTERNS.md — Full-page composition patterns and integration recipes
- API.md — Auto-generated prop reference from official component docs — covers all 17 components
Official Documentation
Bubble
Common Props Reference: Common Props
Bubble
<!-- prettier-ignore -->
| Attribute | Description | Type | Default | Version |
|---|---|---|---|---|
| placement | Bubble position | start \ | end | start |
| loading | Loading state | boolean | - | - |
| loadingRender | Custom loading content renderer | () => React.ReactNode | - | - |
| content | Bubble content | ContentType | - | - |
| contentRender | Custom content renderer | (content: ContentType, info: InfoType ) => React.ReactNode | - | - |
| editable | Editable | boolean \ | EditableBubbleOption | false |
| typing | Typing animation effect | boolean \ | BubbleAnimationOption \ | ((content: ContentType, info: InfoType) => boolean \ |
| streaming | Streaming mode | boolean | false | - |
| variant | Bubble style variant | filled \ | outlined \ | shadow \ |
| shape | Bubble shape | default \ | round \ | corner |
| footerPlacement | Footer slot position | outer-start \ | outer-end \ | inner-start \ |
| header | Header slot | BubbleSlot | - | - |
| footer | Footer slot | BubbleSlot | - | - |
| avatar | Avatar slot | BubbleSlot | - | - |
| extra | Extra slot | BubbleSlot | - | - |
| onTyping | Typing animation callback | (rendererContent: string, currentContent: string) => void | - | 2.0.0 |
| onTypingComplete | Typing animation complete callback | (content: string) => void | - | - |
| onEditConfirm | Edit confirm callback | (content: string) => void | - | 2.0.0 |
| onEditCancel | Edit cancel callback | () => void | - | 2.0.0 |
ContentType
Default type
type ContentType = React.ReactNode | AnyObject | string | number;Custom type usage
type CustomContentType {
...
}
<Bubble<CustomContentType> {...props} />BubbleSlot
type BubbleSlot<ContentType> =
| React.ReactNode
| ((content: ContentType, info: InfoType) => React.ReactNode);EditableBubbleOption
interface EditableBubbleOption {
/**
* @description Whether editable
*/
editing?: boolean;
/**
* @description OK button
*/
okText?: React.ReactNode;
/**
* @description Cancel button
*/
cancelText?: React.ReactNode;
}BubbleAnimationOption
interface BubbleAnimationOption {
/**
* @description Animation effect type, typewriter, fade-in
* @default 'fade-in'
*/
effect: 'typing' | 'fade-in';
/**
* @description Content step unit, array format for random interval
* @default 6
*/
step?: number | [number, number];
/**
* @description Animation trigger interval
* @default 100
*/
interval?: number;
/**
* @description Whether to keep the common prefix when restarting animation
* @default true
*/
keepPrefix?: boolean;
}streaming
streaming notifies Bubble whether the current content is streaming input. In streaming mode, regardless of whether Bubble input animation is enabled, Bubble will not trigger the onTypingComplete callback until streaming becomes false, even if the current content is fully output. Only when streaming becomes false and the content is fully output will Bubble trigger onTypingComplete. This avoids multiple triggers due to unstable streaming and ensures only one trigger per streaming process.
In this example, you can try to force the streaming flag off:
- If you enable input animation and perform slow loading, multiple triggers of
onTypingCompletemay occur because streaming speed cannot keep up with animation speed. - If you disable input animation, each streaming input will trigger
onTypingComplete.
Bubble.List
| Attribute | Description | Type | Default | Version |
|---|---|---|---|---|
| items | Bubble data list, key and role required. When used with X SDK `useXChat`, you can pass status to help Bubble manage configuration | (BubbleProps & { key: string \ | number, role: string , status: MessageStatus, extraInfo?: AnyObject })[] | - |
| autoScroll | Auto-scroll | boolean | true | - |
| role | Role default configuration | RoleType | - | - |
MessageStatus
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';InfoType
When used in conjunction with `useXChat`, key can be used as MessageId,and extraInfo can be used as a custom parameter.
type InfoType = {
status?: MessageStatus;
key?: string | number;
extraInfo?: AnyObject;
};RoleType
export type RoleProps = Pick<
BubbleProps<any>,
| 'typing'
| 'variant'
| 'shape'
| 'placement'
| 'rootClassName'
| 'classNames'
| 'className'
| 'styles'
| 'style'
| 'loading'
| 'loadingRender'
| 'contentRender'
| 'footerPlacement'
| 'header'
| 'footer'
| 'avatar'
| 'extra'
| 'editable'
| 'onTyping'
| 'onTypingComplete'
| 'onEditConfirm'
| 'onEditCancel'
>;
export type FuncRoleProps = (data: BubbleItemType) => RoleProps;
export type DividerRoleProps = Partial<DividerBubbleProps>;
export type FuncDividerRoleProps = (data: BubbleItemType) => DividerRoleProps;
export type RoleType = Partial<Record<'ai' | 'system' | 'user', RoleProps | FuncRoleProps>> & {
divider?: DividerRoleProps | FuncDividerRoleProps;
} & Record<string, RoleProps | FuncRoleProps>;Bubble.List autoScroll Top Alignment
Bubble.List auto-scroll is a simple reverse sorting scheme. In a fixed-height Bubble.List, if the message content is insufficient to fill the height, the content is bottom-aligned. It is recommended not to set a fixed height for Bubble.List, but to set a fixed height for its parent container and use flex layout (display: flex and flex-direction: column). This way, Bubble.List adapts its height and aligns content to the top when content is sparse, as shown in the Bubble List demo.
<div style={{ height: 600, display: 'flex', flexDirection: 'column' }}>
<Bubble.List items={items} autoScroll />
</div>If you do not want to use flex layout, you can set max-height for Bubble.List. When content is sparse, the height adapts and aligns to the top.
<Bubble.List items={items} autoScroll style={{ maxHeight: 600 }} />Bubble.List role and Custom Bubble
Both the role and items attributes of Bubble.List can be configured for bubbles, where the role configuration is used as the default and can be omitted. item.role is used to specify the bubble role for the data item, which will be matched with Bubble.List.role. The items itself can also be configured with bubble attributes, with higher priority than the role configuration. The final bubble configuration is: { ...role[item.role], ...item }.
Note that semantic configuration in Bubble.List can also style the bubbles, but it has the lowest priority and will be overridden by role or items.
The final configuration priority is: items > role > Bubble.List.styles = Bubble.List.classNames.
Special note: We provide four default fields for role, ai, user, system, divider. Among these, system and divider are reserved fields. If item.role is assigned either of them, Bubble.List will render this bubble data as Bubble.System (role = 'system') or Bubble.Divider (role = 'divider').
Therefore, if you want to customize the rendering of system Bubble or divider Bubble, you should use other names.
Customize the rendering Bubble, you can refer to the rendering method of reference in this example.
Bubble.System
Common Props Reference: Common Props
| Attribute | Description | Type | Default | Version |
|---|---|---|---|---|
| content | Bubble content | ContentType | - | - |
| variant | Bubble style variant | filled \ | outlined \ | shadow \ |
| shape | Bubble shape | default \ | round \ | corner |
Bubble.Divider
Common Props Reference: Common Props
| Attribute | Description | Type | Default | Version |
|---|---|---|---|---|
| content | Bubble content,same as Divider.children | ContentType | - | - |
| dividerProps | Divider props | Divider | - | - |
---
Sender
Common props ref:Common props
SenderProps
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
| allowSpeech | Whether to allow voice input | boolean \ | SpeechConfig | false |
| classNames | Style class names | See below | - | - |
| components | Custom components | Record<'input', ComponentType> | - | - |
| defaultValue | Default value of the input box | string | - | - |
| disabled | Whether to disable | boolean | false | - |
| loading | Whether in loading state | boolean | false | - |
| suffix | Suffix content, displays action buttons by default. When you don't need the default action buttons, you can set suffix={false} | React.ReactNode \ | false \ | (oriNode: React.ReactNode, info: { components: ActionsComponents; }) => React.ReactNode \ |
| header | Header panel | React.ReactNode \ | false \ | (oriNode: React.ReactNode, info: { components: ActionsComponents; }) => React.ReactNode \ |
| prefix | Prefix content | React.ReactNode \ | false \ | (oriNode: React.ReactNode, info: { components: ActionsComponents; }) => React.ReactNode \ |
| footer | Footer content | React.ReactNode \ | false \ | (oriNode: React.ReactNode, info: { components: ActionsComponents; }) => React.ReactNode \ |
| readOnly | Whether to make the input box read-only | boolean | false | - |
| rootClassName | Root element style class | string | - | - |
| styles | Semantic style definition | See below | - | - |
| submitType | Submission mode | SubmitType | enter \ | shiftEnter |
| value | Input box value | string | - | - |
| onSubmit | Callback for clicking the send button | (message: string, slotConfig: SlotConfigType[], skill: SkillType) => void | - | - |
| onChange | Callback for input box value change | (value: string, event?: React.FormEvent<HTMLTextAreaElement> \ | React.ChangeEvent<HTMLTextAreaElement>, slotConfig: SlotConfigType[], skill: SkillType) => void | - |
| onCancel | Callback for clicking the cancel button | () => void | - | - |
| onPaste | Callback for pasting | React.ClipboardEventHandler<HTMLElement> | - | - |
| onPasteFile | Callback for pasting files | (files: FileList) => void | - | - |
| onKeyDown | Callback for keyboard press | (event: React.KeyboardEvent) => void \ | false | - |
| onFocus | Callback for getting focus | React.FocusEventHandler<HTMLTextAreaElement> | - | - |
| onBlur | Callback for losing focus | React.FocusEventHandler<HTMLTextAreaElement> | - | - |
| placeholder | Placeholder of the input box | string | - | - |
| autoSize | Auto-adjust content height, can be set to true \ | false or object: { minRows: 2, maxRows: 6 } | boolean \ | { minRows?: number; maxRows?: number } |
| slotConfig | Slot configuration, after configuration the input box will switch to slot mode, supporting structured input. In this mode, value and defaultValue configurations will be invalid. | SlotConfigType[] | - | 2.0.0 |
| skill | Skill configuration, the input box will switch to slot mode, supporting structured input. In this mode, value and defaultValue configurations will be invalid. | SkillType | - | 2.0.0 |
```typescript | pure interface SkillType { title?: React.ReactNode; value: string; toolTip?: TooltipProps; closable?: | boolean | { closeIcon?: React.ReactNode; onClose?: React.MouseEventHandler<HTMLDivElement>; disabled?: boolean; }; }
type SpeechConfig = { // When recording is set, the built-in voice input feature will be disabled. // Developers need to implement third-party voice input functionality. recording?: boolean; onRecordingChange?: (recording: boolean) => void; };
type ActionsComponents = { SendButton: React.ComponentType<ButtonProps>; ClearButton: React.ComponentType<ButtonProps>; LoadingButton: React.ComponentType<ButtonProps>; SpeechButton: React.ComponentType<ButtonProps>; };
### Sender Ref
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| inputElement | Input element | `HTMLTextAreaElement` | - | - |
| nativeElement | Outer container | `HTMLDivElement` | - | - |
| focus | Get focus, when `cursor = 'slot'` the focus will be in the first slot of type `input`, if no corresponding `input` exists it will behave the same as `end` | (option?: { preventScroll?: boolean, cursor?: 'start' \| 'end' \| 'all' \| 'slot' }) | - | - |
| blur | Remove focus | () => void | - | - |
| insert | Insert text or slots, when using slots ensure slotConfig is configured | (value: string) => void \| (slotConfig: SlotConfigType[], position: insertPosition, replaceCharacters: string, preventScroll: boolean) => void; | - | - |
| clear | Clear content | () => void | - | - |
| getValue | Get current content and structured configuration | () => { value: string; slotConfig: SlotConfigType[], skill: SkillType } | - | - |
#### SlotConfigType
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| type | Node type, determines the rendering component type, required | 'text' \| 'input' \| 'select' \| 'tag' \| 'content' \| 'custom' | - | 2.0.0 |
| key | Unique identifier, can be omitted when type is text | string | - | - |
| formatResult | Format the final result | (value: any) => string | - | 2.0.0 |
##### text node properties
| Property | Description | Type | Default | Version |
| -------- | ------------ | ------ | ------- | ------- |
| value | Text content | string | - | 2.0.0 |
##### input node properties
| Property | Description | Type | Default | Version |
| ------------------ | ------------- | ------------------------------------- | ------- | ------- |
| props.placeholder | Placeholder | string | - | 2.0.0 |
| props.defaultValue | Default value | string \| number \| readonly string[] | - | 2.0.0 |
##### select node properties
| Property | Description | Type | Default | Version |
| ------------------ | ----------------------- | -------- | ------- | ------- |
| props.options | Options array, required | string[] | - | 2.0.0 |
| props.placeholder | Placeholder | string | - | 2.0.0 |
| props.defaultValue | Default value | string | - | 2.0.0 |
##### tag node properties
| Property | Description | Type | Default | Version |
| ----------- | --------------------- | --------- | ------- | ------- |
| props.label | Tag content, required | ReactNode | - | 2.0.0 |
| props.value | Tag value | string | - | 2.0.0 |
##### content node properties
| Property | Description | Type | Default | Version |
| ------------------ | ------------- | ------ | ------- | ------- |
| props.defaultValue | Default value | any | - | 2.1.0 |
| props.placeholder | Placeholder | string | - | 2.1.0 |
##### custom node properties
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| props.defaultValue | Default value | any | - | 2.0.0 |
| customRender | Custom rendering function | (value: any, onChange: (value: any) => void, props: { disabled?: boolean, readOnly?: boolean }, item: SlotConfigType) => React.ReactNode | - | 2.0.0 |
### Sender.Header
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| children | Panel content | ReactNode | - | - |
| classNames | Style class names | [See below](#semantic-dom) | - | - |
| closable | Whether it can be closed | boolean | true | - |
| forceRender | Force rendering, use when you need to reference internal elements during initialization | boolean | false | - |
| open | Whether to expand | boolean | - | - |
| styles | Semantic style definition | [See below](#semantic-dom) | - | - |
| title | Title | ReactNode | - | - |
| onOpenChange | Callback for expansion state change | (open: boolean) => void | - | - |
### Sender.Switch
| Property | Description | Type | Default | Version |
| ----------------- | ------------------------ | -------------------------- | ------- | ------- |
| children | General content | ReactNode | - | 2.0.0 |
| checkedChildren | Content when checked | ReactNode | - | 2.0.0 |
| unCheckedChildren | Content when unchecked | ReactNode | - | 2.0.0 |
| icon | Set icon component | ReactNode | - | 2.0.0 |
| disabled | Whether disabled | boolean | false | 2.0.0 |
| loading | Loading switch | boolean | - | 2.0.0 |
| defaultValue | Default checked state | boolean | - | 2.0.0 |
| value | Switch value | boolean | false | 2.0.0 |
| onChange | Callback when changed | function(checked: boolean) | - | 2.0.0 |
| rootClassName | Root element style class | string | - | 2.0.0 |
### ⚠️ Slot Mode Notes
- **In slot mode, `value` and `defaultValue` properties are invalid**, please use `ref` and callback events to get the input box value and slot configuration.
- **In slot mode, the third parameter `config` of `onChange`/`onSubmit` callbacks** is only used to get the current structured content.
**Example:**
// ❌ Incorrect usage, slotConfig and skill are for uncontrolled usage const [config, setConfig] = useState([]); const [skill, setSkill] = useState([]); <Sender slotConfig={config} skill={skill} onChange={(value, e, config, skill) => { setConfig(config); setSkill(skill) }} />
// ✅ Correct usage <Sender key={key} slotConfig={config} skill={skill} onChange={(value, _e, config, skill) => { // Only used to get structured content setKey('new_key') }} />
---
## Conversations
Common props ref:[Common props](/docs/react/common-props)
### ConversationsProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| activeKey | Currently selected value | string | - | - |
| defaultActiveKey | Default selected value | string | - | - |
| items | Data source for conversation list | `ItemType`[] | - | - |
| onActiveChange | Callback for selection change | (value: string, item: ItemType) => void | - | - |
| menu | Operation menu for conversations | ItemMenuProps\| ((conversation: ConversationItemType) => ItemMenuProps) | - | - |
| groupable | If grouping is supported, it defaults to the `Conversation.group` field | boolean \| GroupableProps | - | - |
| shortcutKeys | Shortcut key operations | { creation?: ShortcutKeys<number>; items?:ShortcutKeys<'number'> \| ShortcutKeys<number>[];} | - | 2.0.0 |
| creation | New conversation configuration | CreationProps | - | 2.0.0 |
| styles | Semantic structure styles | styles?: {creation?: React.CSSProperties;item?: React.CSSProperties;} | - | - |
| classNames | Semantic structure class names | classNames?: { creation?: string; item?:string;} | - | - |
| rootClassName | Root node className | string | - | - |
### ItemType
type ItemType = ConversationItemType | DividerItemType;
#### ConversationItemType
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| key | Unique identifier | string | - | - |
| label | Conversation name | React.ReactNode | - | - |
| group | Conversation type, linked to `ConversationsProps.groupable` | string | - | - |
| icon | Conversation icon | React.ReactNode | - | - |
| disabled | Whether to disable | boolean | - | - |
#### DividerItemType
| Property | Description | Type | Default | Version |
| -------- | -------------- | --------- | --------- | ------- |
| type | Divider type | 'divider' | 'divider' | - |
| dashed | Whether dashed | boolean | false | - |
### GroupableProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| label | Group title | React.ReactNode\| ((group: string, info: { groupInfo: GroupInfoType}) => React.ReactNode) | - | - |
| collapsible | Collapsible configuration | boolean \| ((group: string) => boolean) | - | - |
| defaultExpandedKeys | Default expanded or collapsed groups | string[] | - | - |
| onExpand | Expand or collapse callback | (expandedKeys: string[]) => void | - | - |
| expandedKeys | Expanded group keys | string[] | - | - |
### ItemMenuProps
Inherits antd [MenuProps](https://ant.design/components/menu-cn#api) properties.
MenuProps & { trigger?: | React.ReactNode | (( conversation: ConversationItemType, info: { originNode: React.ReactNode }, ) => React.ReactNode); getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement; };
---
## Welcome
### WelcomeProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| classNames | Custom style class names for different parts of each prompt item. | Record<'icon' \| 'title' \| 'description' \| 'extra', string> | - | - |
| description | The description displayed in the prompt list. | React.ReactNode | - | - |
| extra | The extra operation displayed at the end of the prompt list. | React.ReactNode | - | - |
| icon | The icon displayed on the front side of the prompt list. | React.ReactNode | - | - |
| rootClassName | The style class name of the root node. | string | - | - |
| styles | Custom styles for different parts of each prompt item. | Record<'icon' \| 'title' \| 'description' \| 'extra', React.CSSProperties> | - | - |
| title | The title displayed at the top of the prompt list. | React.ReactNode | - | - |
| variant | Variant type. | 'filled' \| 'borderless' | 'filled' | - |
---
## Prompts
### PromptsProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| classNames | Custom style class names for different parts of each prompt item. | Record<SemanticType, string> | - | - |
| items | List containing multiple prompt items. | PromptProps[] | - | - |
| prefixCls | Prefix for style class names. | string | - | - |
| rootClassName | Style class name for the root node. | string | - | - |
| styles | Custom styles for different parts of each prompt item. | Record<SemanticType, React.CSSProperties> | - | - |
| title | Title displayed at the top of the prompt list. | React.ReactNode | - | - |
| vertical | When set to `true`, the Prompts will be arranged vertically. | boolean | `false` | - |
| wrap | When set to `true`, the Prompts will automatically wrap. | boolean | `false` | - |
| onItemClick | Callback function when a prompt item is clicked. | (info: { data: PromptProps }) => void | - | - |
| fadeIn | Fade in effect | boolean | - | - |
| fadeInLeft | Fade left in effect | boolean | - | - |
### PromptProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| children | Nested child prompt items. | PromptProps[] | - | - |
| description | Prompt description providing additional information. | React.ReactNode | - | - |
| disabled | When set to `true`, click events are disabled. | boolean | `false` | - |
| icon | Prompt icon displayed on the left side of the prompt item. | React.ReactNode | - | - |
| key | Unique identifier used to distinguish each prompt item. | string | - | - |
| label | Prompt label displaying the main content of the prompt. | React.ReactNode | - | - |
---
## Attachments
Common props ref: [Common props](/docs/react/common-props).
### AttachmentsProps
Inherits antd [Upload](https://ant.design/components/upload) properties.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| classNames | Custom class names, [see below](#semantic-dom) | Record<string, string> | - | - |
| disabled | Whether to disable | boolean | false | - |
| maxCount | Maximum number of files for upload | number \| - | - | 2.0.0 |
| getDropContainer | Config the area where files can be dropped | () => HTMLElement | - | - |
| items | Attachment list, same as Upload `fileList` | Attachment[] | - | - |
| overflow | Behavior when the file list overflows | 'wrap' \| 'scrollX' \| 'scrollY' | - | - |
| placeholder | Placeholder information when there is no file | PlaceholderType \| ((type: 'inline' \| 'drop') => PlaceholderType) | - | - |
| rootClassName | Root node className | string | - | - |
| styles | Custom style object, [see below](#semantic-dom) | Record<string, React.CSSProperties> | - | - |
| imageProps | Image config, same as antd [Image](https://ant.design/components/image) | ImageProps | - | - |
interface PlaceholderType { icon?: React.ReactNode; title?: React.ReactNode; description?: React.ReactNode; }
### AttachmentsRef
| Property | Description | Type | Version |
| --- | --- | --- | --- |
| nativeElement | Get the native node | HTMLElement | - |
| fileNativeElement | Get the file upload native node | HTMLElement | - |
| upload | Manually upload a file | (file: File) => void | - |
| select | Manually select files | (options: { accept?: string; multiple?: boolean; }) => void | 2.0.0 |
---
## Suggestion
Common props ref:[Common props](/docs/react/common-props)
For more configuration, please check [CascaderProps](https://ant.design/components/cascader#api)
### SuggestionsProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| block | Take up the full width | boolean | false | - |
| children | Custom input box | ({ onTrigger, onKeyDown }) => ReactElement | - | - |
| items | Suggestion list | SuggestionItem[] \| ((info: T) => SuggestionItem[]) | - | - |
| open | Controlled open panel | boolean | - | - |
| rootClassName | Root element class name | string | - | - |
| onSelect | Callback when the suggestion item is selected | (value: string, selectedOptions: SuggestionItem[]) => void; | - | - |
| onOpenChange | Callback when the panel open state changes | (open: boolean) => void | - | - |
| getPopupContainer | The parent node of the menu. Default is to render to body. If you encounter menu scrolling positioning issues, try modifying it to the scrolling area and positioning relative to it | (triggerNode: HTMLElement) => HTMLElement | () => document.body | - |
#### onTrigger
type onTrigger<T> = (info: T | false) => void;
Suggestion accepts generics to customize the parameter type passed to `items` renderProps. When `false` is passed, the suggestion panel is closed.
### SuggestionItem
| Property | Description | Type | Default | Version |
| -------- | ------------------------------------- | ---------------- | ------- | ------- |
| children | Child item for the suggestion item | SuggestionItem[] | - | - |
| extra | Extra content for the suggestion item | ReactNode | - | - |
| icon | Icon for the suggestion | ReactNode | - | - |
| label | Content to display for the suggestion | ReactNode | - | - |
| value | Value of the suggestion item | string | - | - |
---
## Think
Common props ref:[Common props](/docs/react/common-props)
### ThinkProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| classNames | DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | - |
| styles | DOM style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | - |
| children | Think Content | React.ReactNode | - | - |
| title | Text of status | React.ReactNode | - | - |
| icon | Show icon | React.ReactNode | - | - |
| loading | Loading | boolean \| React.ReactNode | false | - |
| defaultExpanded | Default Expand state | boolean | true | - |
| expanded | Expand state | boolean | - | - |
| onExpand | Callback when expand changes | (expand: boolean) => void | - | - |
| blink | Blink mode | boolean | - | - |
---
## ThoughtChain
Reference: [Common API](/docs/react/common-props)
### ThoughtChainProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| items | Collection of thought nodes | ThoughtChainItemType[] | - | - |
| defaultExpandedKeys | Initially expanded nodes | string[] | - | - |
| expandedKeys | Currently expanded nodes | string[] | - | - |
| onExpand | Callback for when expanded nodes change | (expandedKeys: string[]) => void; | - | - |
| line | Line style, no line is shown when `false` | boolean \| 'solid' \| 'dashed' \| 'dotted' | 'solid' | - |
| classNames | Class names for semantic structure | Record<'root'\|'item' \| 'itemIcon'\|'itemHeader' \| 'itemContent' \| 'itemFooter', string> | - | - |
| prefixCls | Custom prefix | string | - | - |
| styles | Styles for semantic structure | Record<'root'\|'item' \|'itemIcon'\| 'itemHeader' \| 'itemContent' \| 'itemFooter', React.CSSProperties> | - | - |
| rootClassName | Root element class name | string | - | - |
### ThoughtChainItemType
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| content | Content of the thought node | React.ReactNode | - | - |
| description | Description of the thought node | React.ReactNode | - | - |
| footer | Footer of the thought node | React.ReactNode | - | - |
| icon | Icon of the thought node, not displayed when `false` | false \| React.ReactNode | DefaultIcon | - |
| key | Unique identifier for the thought node | string | - | - |
| status | Status of the thought node | 'loading' \| 'success' \| 'error'\| 'abort' | - | - |
| title | Title of the thought node | React.ReactNode | - | - |
| collapsible | Whether the thought node is collapsible | boolean | false | - |
| blink | Blink mode | boolean | - | - |
### ThoughtChain.Item
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| prefixCls | Custom prefix | string | - | - |
| icon | Icon of the thought chain | React.ReactNode | - | - |
| title | Title of the thought chain | React.ReactNode | - | - |
| description | Description of the thought chain | React.ReactNode | - | - |
| status | Status of the thought chain | 'loading' \| 'success' \| 'error'\| 'abort' | - | - |
| variant | Variant configuration | 'solid' \| 'outlined' \| 'text' | - | - |
| blink | Blink mode | boolean | - | - |
---
## Actions
Common props ref:[Common props](/docs/react/common-props)
### ActionsProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| items | List containing multiple action items | ([ItemType](#itemtype) \| ReactNode)[] | - | - |
| onClick | Callback function when component is clicked | function({ item, key, keyPath, domEvent }) | - | - |
| dropdownProps | Configuration properties for dropdown menu | DropdownProps | - | - |
| variant | Variant | `borderless` \| `outlined` \|`filled` | `borderless` | - |
| fadeIn | Fade in effect | boolean | - | 2.0.0 |
| fadeInLeft | Fade left in effect | boolean | - | 2.0.0 |
### ItemType
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| key | Unique identifier for custom action | string | - | - |
| label | Display label for custom action | string | - | - |
| icon | Icon for custom action | ReactNode | - | - |
| onItemClick | Callback function when custom action button is clicked | (info: [ItemType](#itemtype)) => void | - | - |
| danger | Syntactic sugar, sets danger icon | boolean | false | - |
| subItems | Sub action items | Omit<ItemType, 'subItems' \| 'triggerSubMenuAction' \| 'actionRender'>[] | - | - |
| triggerSubMenuAction | Action to trigger the sub-menu | `hover` \| `click` | `hover` | - |
| actionRender | Custom render action item content | (item: [ItemType](#itemtype)) => ReactNode | - | - |
### Actions.Feedback
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| value | Feedback status value | `like` \| `dislike` \| `default` | `default` | 2.0.0 |
| onChange | Feedback status change callback | (value: `like` \| `dislike` \| `default`) => void | - | 2.0.0 |
### Actions.Copy
| Property | Description | Type | Default | Version |
| -------- | ----------------- | --------------- | ------- | ------- |
| text | Text to be copied | string | '' | 2.0.0 |
| icon | Copy button | React.ReactNode | - | 2.0.0 |
### Actions.Audio
| Property | Description | Type | Default | Version |
| -------- | --------------- | ---------------------------------------- | ------- | ------- |
| status | Playback status | 'loading'\|'error'\|'running'\|'default' | default | 2.0.0 |
### Actions.Item
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| status | Status | 'loading'\|'error'\|'running'\|'default' | default | 2.0.0 |
| label | Display label for custom action | string | - | 2.0.0 |
| defaultIcon | Default status icon | ReactNode | - | 2.0.0 |
| runningIcon | Running status icon | ReactNode | - | 2.0.0 |
---
## FileCard
Common props ref:[Common props](/docs/react/common-props)
### FileCardProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| name | File name | string | - | - |
| byte | File size (bytes) | number | - | - |
| size | Card size | 'small' \| 'default' | 'default' | - |
| description | File description, supports function form to get context information | React.ReactNode \| ((info: { size: string, icon: React.ReactNode, namePrefix?: string, nameSuffix?: string, name?: string, src?: string, type?: string }) => React.ReactNode) | - | - |
| loading | Loading state | boolean | false | - |
| type | File type | 'file' \| 'image' \| 'audio' \| 'video' \| string | - | - |
| src | Image or file URL | string | - | - |
| mask | Mask content, supports function form to get context information. For `type="image"`, this is configured via `imageProps.preview.mask`,This prop only applies to non-image file types. | React.ReactNode \| ((info: { size: string, icon: React.ReactNode, namePrefix?: string, nameSuffix?: string, name?: string, src?: string, type?: string }) => React.ReactNode) | - | - |
| icon | Custom icon | React.ReactNode \| PresetIcons | - | - |
| imageProps | Image props configuration | [Image](https://ant.design/components/image-cn#api) | - | - |
| videoProps | Video props configuration | Partial<React.JSX.IntrinsicElements['video']> | - | - |
| audioProps | Audio props configuration | Partial<React.JSX.IntrinsicElements['audio']> | - | - |
| spinProps | Loading animation props configuration | [SpinProps](https://ant.design/components/spin-cn#api) & { showText?: boolean; icon?: React.ReactNode } | - | - |
| onClick | Click event callback, receives file information and click event | (info: { size: string, icon: React.ReactNode, namePrefix?: string, nameSuffix?: string, name?: string, src?: string, type?: string }, event: React.MouseEvent\<HTMLDivElement\>) => void | - | - |
### PresetIcons
Preset icon types, supports the following values:
type PresetIcons = | 'default' // Default file icon | 'excel' // Excel file icon | 'image' // Image file icon | 'markdown' // Markdown file icon | 'pdf' // PDF file icon | 'ppt' // PowerPoint file icon | 'word' // Word file icon | 'zip' // Archive file icon | 'video' // Video file icon | 'audio' // Audio file icon | 'java' // Java file icon | 'javascript' // JavaScript file icon | 'python'; // Python file icon
### FileCard.List
File list component for displaying multiple file cards.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| items | File list data | FileCardProps[] | - | - |
| size | Card size | 'small' \| 'default' | 'default' | - |
| removable | Whether removable | boolean \| ((item: FileCardProps) => boolean) | false | - |
| onRemove | Remove event callback | (item: FileCardProps) => void | - | - |
| extension | Extension content | React.ReactNode | - | - |
| overflow | Overflow display style | 'scrollX' \| 'scrollY' \| 'wrap' | 'wrap' | - |
---
## Sources
Common props ref:[Common props](/docs/react/common-props)
### SourcesProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| classNames | DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | - |
| styles | DOM style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | - |
| title | Title content | React.ReactNode | - | - |
| items | Sources content list | SourcesItem[] | - | - |
| expandIconPosition | Expand icon position | 'start' \| 'end' | 'start' | - |
| defaultExpanded | Default expand state | boolean | true | - |
| expanded | Expand state | boolean | - | - |
| onExpand | Callback when expand changes | (expand: boolean) => void | - | - |
| onClick | Callback when click | (item: SourcesItem) => void | - | - |
| inline | Inline mode | boolean | false | - |
| activeKey | Active key in inline mode | React.Key | - | - |
| popoverOverlayWidth | Popover overlay width | number \| string | 300 | - |
interface SourcesItem { key?: React.Key; title: React.ReactNode; url?: string; icon?: React.ReactNode; description?: React.ReactNode; }
---
## CodeHighlighter
For common properties, refer to: [Common Properties](/docs/react/common-props).
### CodeHighlighterProps
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| lang | Language | `string` | - |
| children | Code content | `string` | - |
| header | Header content, set to `false` to hide the header | `React.ReactNode \| (() => React.ReactNode \| false) \| false` | - |
| className | Style class name | `string` | |
| classNames | Style class names | `string` | - |
| highlightProps | Code highlighting configuration | [`highlightProps`](https://github.com/react-syntax-highlighter/react-syntax-highlighter?tab=readme-ov-file#props) | - |
| prismLightMode | Whether to use Prism light mode to automatically load language support based on lang prop for smaller bundle size | `boolean` | `true` |
### CodeHighlighterRef
| Property | Description | Type | Version |
| ------------- | ------------------ | ----------- | ------- |
| nativeElement | Get native element | HTMLElement | - |
---
## Mermaid
<!-- prettier-ignore -->
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| children | Code content | `string` | - |
| header | Header | `React.ReactNode \| null` | React.ReactNode |
| className | Style class name | `string` | - |
| classNames | Style class name | `Partial<Record<'root' \| 'header' \| 'graph' \| 'code', string>>` | - |
| styles | Style object | `Partial<Record<'root' \| 'header' \| 'graph' \| 'code', React.CSSProperties>>` | - |
| highlightProps | Code highlighting configuration | [`highlightProps`](https://github.com/react-syntax-highlighter/react-syntax-highlighter?tab=readme-ov-file#props) | - |
| config | Mermaid configuration | `MermaidConfig` | - |
| actions | Actions configuration | `{ enableZoom?: boolean; enableDownload?: boolean; enableCopy?: boolean; customActions?: ItemType[] }` | `{ enableZoom: true, enableDownload: true, enableCopy: true }` |
| onRenderTypeChange | Callback when render type changes | `(value: 'image' \| 'code') => void` | - |
| prefixCls | Style prefix | `string` | - |
| style | Custom style | `React.CSSProperties` | - |
---
## XProvider
`XProvider` fully extends `antd`'s `ConfigProvider`. Props ref:[Antd ConfigProvider](https://ant-design.antgroup.com/components/config-provider-cn#api)
### Component Config
<!-- prettier-ignore -->
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| bubble | Global configuration for the Bubble component | {style: React.CSSProperties; styles: Record<string, React.CSSProperties>;className: string; classNames: Record<string, string>;} | - | - |
| conversations | Global configuration for the Conversations component | {style: React.CSSProperties; styles: Record<string, React.CSSProperties>;className: string; classNames: Record<string, string>;shortcutKeys: {items?: ShortcutKeys<'number'> \| ShortcutKeys<number>[]}} | - | - |
| prompts | Global configuration for the Prompts component | {style: React.CSSProperties; styles: Record<string, React.CSSProperties>;className: string; classNames: Record<string, string>;} | - | - |
| sender | Global configuration for the Sender component | {style: React.CSSProperties; styles: Record<string, React.CSSProperties>;className: string; classNames: Record<string, string>;} | - | - |
| suggestion | Global configuration for the Suggestion component | {style: React.CSSProperties; className: string;} | - | |
| thoughtChain | Global configuration for the ThoughtChain component | {style: React.CSSProperties; styles: Record<string, React.CSSProperties>;className: string; classNames: Record<string, string>;}| - | |
| actions | Global configuration for the Actions component | {style: React.CSSProperties; className: string;}| - | |
#### ShortcutKeys
type SignKeysType = { Ctrl: keyof KeyboardEvent; Alt: keyof KeyboardEvent; Meta: keyof KeyboardEvent; Shift: keyof KeyboardEvent; }; type ShortcutKeys<CustomKey = number | 'number'> = | [keyof SignKeysType, keyof SignKeysType, CustomKey] | [keyof SignKeysType, CustomKey];
---
## Notification
To successfully send a notification, you need to ensure that the current domain has been granted notification permission.
### XNotification
<!-- prettier-ignore -->
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| permission | Indicates whether the user has granted permission to display web notifications for the current origin. | NotificationPermission | - | - |
| requestPermission| Requests permission from the user to display notifications for the current origin. | ()=> Promise</NotificationPermission/> | - | - |
| open |Push a notification to the user| (config: XNotificationOpenArgs)=> void | - | - |
| close|Close pushed notifications. You can pass a tag list to close specific notifications, or call without arguments to close all.| (config?: string[])=> void | - | - |
#### NotificationPermission
type NotificationPermission = | 'granted' // The user has explicitly granted the current origin permission to display system notifications. | 'denied' // The user has explicitly denied the current origin permission to display system notifications. | 'default'; // The user's decision is unknown; in this case, the application behaves as if the permission was "denied".
#### XNotificationOpenArgs
type XNotificationOpenArgs = { openConfig: NotificationOptions & { title: string; onClick?: (event: Event, close?: Notification['close']) => void; onClose?: (event: Event) => void; onError?: (event: Event) => void; onShow?: (event: Event) => void; duration?: number; }; closeConfig: NotificationOptions['tag'][]; };
#### NotificationOptions
interface NotificationOptions { badge?: string; body?: string; data?: any; dir?: NotificationDirection; icon?: string; lang?: string; requireInteraction?: boolean; silent?: boolean | null; tag?: string; }
### useNotification
type useNotification = [ { permission: XNotification['permission'] }, { open: XNotification['open']; close: XNotification['close']; requestPermission: XNotification['requestPermission']; }, ];
## System Permission Settings
### Change `Notification` settings on Windows
The setting path for different versions of the Windows system will be different. You can refer to the approximate path: "Start" menu > "Settings" > "System" > and then select "Notifications & actions" on the left, after which you can operate on global notifications and application notifications.
### Change `Notification` settings on Mac
On a Mac, use the "Notifications" settings to specify the period during which you do not want to be disturbed by notifications, and control how notifications are displayed in the "Notification Center". To change these settings, choose "Apple" menu > "System Settings", then click "Notifications" in the sidebar (you may need to scroll down).
## FAQ
### I have obtained the permission for the current `origin` to display system notifications, and the `onShow` callback has also been triggered. Why can't the pushed notification be displayed?
`Notification` is a system-level feature. Please ensure that notifications are enabled for the browser application on your device.
---
## Folder
Common props ref: [Common props](/docs/react/common-props)
### FolderProps
<!-- prettier-ignore -->
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| treeData | File tree data | [FolderTreeData](#foldertreedata)[] | `[]` | - |
| selectable | Whether to enable selection functionality | boolean | `true` | - |
| selectedFile | Selected file paths (controlled) | string[] | - | - |
| defaultSelectedFile | Default selected file paths | string[] | `[]` | - |
| onSelectedFileChange | Callback when file selection changes | (file: { path: string[]; name?: string; content?: string }) => void | - | - |
| directoryTreeWith | Directory tree width | number \| string | `278` | - |
| emptyRender | Content to display when empty, set to `false` to hide | false \| React.ReactNode \| (() => React.ReactNode) | - | - |
| previewRender | Custom file preview content | React.ReactNode \| ((file: { content?: string; path: string[]; title?: React.ReactNode; language: string }, info: { originNode: React.ReactNode }) => React.ReactNode) | - | - |
| expandedPaths | Array of expanded node paths (controlled) | string[] | - | - |
| defaultExpandedPaths | Array of default expanded node paths | string[] | - | - |
| defaultExpandAll | Whether to expand all nodes by default | boolean | `true` | - |
| onExpandedPathsChange | Callback when expand/collapse changes | (paths: string[]) => void | - | - |
| fileContentService | File content service | [FileContentService](#filecontentservice) | - | - |
| onFileClick | File click event | (filePath: string, content?: string) => void | - | - |
| onFolderClick | Folder click event | (folderPath: string) => void | - | - |
| directoryTitle | Directory tree title, set to `false` to hide | false \| React.ReactNode \| (() => React.ReactNode) | - | - |
| previewTitle | File preview title | string \| (({ title, path, content }: { title: string; path: string[]; content: string }) => React.ReactNode) | - | - |
| directoryIcons | Custom icon configuration, set to `false` to hide icons | false \| Record<'directory' \| string, React.ReactNode \| (() => React.ReactNode)> | - | - |
### FolderTreeData
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| title | Display name | string | - | - |
| path | File path | string | - | - |
| content | File content (optional) | string | - | - |
| children | Sub-items (valid only for folder type) | [FolderTreeData](#foldertreedata)[] | - | - |
### FileContentService
File content service interface, used for dynamically loading file content.
interface FileContentService { loadFileContent(filePath: string): Promise<string>; }
Component Guide
Bubble
Purpose: Display a single chat message — AI reply or user message.
Key decision: Use Bubble.List when rendering multiple messages. Use Bubble only for a standalone single message.
import { Bubble } from '@ant-design/x';
// Basic
<Bubble content="Hello!" />
// With avatar, header, footer
<Bubble
content="Hello!"
placement="start"
avatar={<Avatar icon={<UserOutlined />} />}
header={<span>Assistant</span>}
footer={(content) => <Actions items={[...]} />}
/>
// Streaming mode — set streaming=false on final chunk
<Bubble
content={streamContent}
streaming={!isDone}
typing={{ effect: 'typing', step: 5, interval: 50 }}
/>Key props:
| Prop | Purpose | | ------------------- | -------------------------------------------------------------------- | ----------------------------------------- | | placement | 'start' (left, AI) or 'end' (right, user) | | content | Message content (string, ReactNode, or custom type) | | streaming | true while streaming, false on last chunk | | typing | Typing animation — false to disable, { effect: 'typing' | 'fade-in', step, interval } to configure | | loading | Show loading skeleton | | header / footer | Slot for metadata or action buttons | | avatar | Slot for avatar | | variant | 'filled' (default) \| 'outlined' \| 'shadow' \| 'borderless' | | shape | 'default' \| 'round' \| 'corner' | | contentRender | Custom renderer for content — use for Markdown or chart components | | editable | Enable inline content editing |
`Bubble.List` — the preferred multi-message component:
import { Bubble } from '@ant-design/x';
const roles = {
assistant: {
placement: 'start',
avatar: <Avatar icon={<RobotOutlined />} />,
},
user: {
placement: 'end',
avatar: <Avatar icon={<UserOutlined />} />,
},
};
<Bubble.List
items={messages.map((msg) => ({
key: msg.id,
role: msg.role, // maps to roles object above
content: msg.content,
loading: msg.loading,
}))}
role={roles}
autoScroll
/>;Bubble.List key props:
| Prop | Purpose |
|---|---|
items | Array of bubble items with key, role, content, and any Bubble prop |
role | Map of role name → default props for that role |
autoScroll | Auto-scroll to bottom on new messages |
---
Sender
Purpose: Chat input box — text entry, file attachment, voice input, submit.
import { Sender } from '@ant-design/x';
import { useState } from 'react';
const [value, setValue] = useState('');
const [loading, setLoading] = useState(false);
<Sender
value={value}
loading={loading}
onChange={(v) => setValue(v)}
onSubmit={(msg) => {
setValue('');
setLoading(true);
// send msg...
}}
onCancel={() => setLoading(false)}
placeholder="Ask anything..."
/>;Key props:
| Prop | Purpose |
|---|---|
value / onChange | Controlled input |
loading | Show cancel button instead of send |
onSubmit | Called when user sends (Enter or button) |
onCancel | Called when user cancels a loading send |
submitType | 'enter' (default) \ |
allowSpeech | Enable voice input (boolean or SpeechConfig) |
header | Expand panel above input (e.g. attachment preview area) |
prefix | Prefix slot (e.g. attachment button) |
suffix | Replace default send button area |
footer | Below-input content |
autoSize | { minRows, maxRows } for textarea auto-resize |
disabled / readOnly | Prevent input |
actions | Custom action items in the default suffix area |
Combining with Attachments:
const [attachments, setAttachments] = useState([]);
<Sender
header={
<Sender.Header>
<Attachments items={attachments} onChange={({ fileList }) => setAttachments(fileList)} />
</Sender.Header>
}
prefix={<Attachments.UploadBtn onChange={({ fileList }) => setAttachments(fileList)} />}
/>;---
Conversations
Purpose: Sidebar list for switching between multiple chat sessions.
import { Conversations } from '@ant-design/x';
<Conversations
items={[
{ key: '1', label: 'Chat with Assistant', icon: <MessageOutlined /> },
{ key: '2', label: 'Code Review', group: 'Today' },
]}
activeKey={activeKey}
onActiveChange={(key) => setActiveKey(key)}
groupable
creation={{
label: 'New Chat',
onClick: () => createNewConversation(),
}}
menu={(conversation) => ({
items: [
{ key: 'rename', label: 'Rename' },
{ key: 'delete', label: 'Delete', danger: true },
],
onClick: ({ key }) => handleMenu(key, conversation),
})}
/>;Key props:
| Prop | Purpose |
|---|---|
items | Array of ConversationItemType — key, label, icon, group, disabled |
activeKey / onActiveChange | Controlled selection |
groupable | Group items by item.group field |
creation | Config for "New Chat" button |
menu | Per-item dropdown menu (rename, delete, etc.) |
---
Welcome + Prompts
Purpose: Onboarding screen shown before the first message.
import { Welcome, Prompts } from '@ant-design/x';
<Welcome
title="Hello, I'm your AI Assistant"
description="Ask me anything, or pick a suggestion below."
icon={<img src={logo} />}
variant="borderless"
/>
<Prompts
title="What would you like to explore?"
items={[
{ key: '1', icon: <SearchOutlined />, label: 'Search the web' },
{ key: '2', icon: <CodeOutlined />, label: 'Write code' },
{ key: '3', icon: <FileOutlined />, label: 'Summarize a document' },
]}
wrap
onItemClick={(info) => handlePromptClick(info.data.label)}
/>Welcome props:
| Prop | Purpose |
|---|---|
title / description | Main content |
icon | App icon / avatar |
extra | Extra actions (top-right) |
variant | 'filled' (default) \ |
Prompts props:
| Prop | Purpose |
|---|---|
items | Array of PromptProps — key, label, description, icon, disabled, children |
title | Section heading |
wrap | Wrap on overflow |
vertical | Stack vertically |
onItemClick | Called with { data: PromptProps } |
fadeIn / fadeInLeft | Entrance animation |
---
ThoughtChain / Think
ThoughtChain
Purpose: Visualize a multi-step agent reasoning chain — tool calls, searches, sub-tasks.
import { ThoughtChain } from '@ant-design/x';
<ThoughtChain
items={[
{
key: '1',
title: 'Search the web',
description: 'query: "React hooks"',
status: 'success',
content: <pre>{searchResults}</pre>,
collapsible: true,
},
{
key: '2',
title: 'Generating answer',
status: 'loading',
blink: true,
},
]}
expandedKeys={expandedKeys}
onExpand={setExpandedKeys}
/>;ThoughtChainItemType:
| Prop | Purpose |
|---|---|
key | Unique identifier |
title | Step name |
description | Short description |
content | Expandable body |
status | 'loading' \ |
icon | Custom icon (false to hide) |
collapsible | Allow collapse/expand |
blink | Animated blink (for in-progress steps) |
Think
Purpose: Collapsible "deep thinking" block — for models that expose a reasoning step.
import { Think } from '@ant-design/x';
<Think title="Thinking..." loading={isStreaming} blink={isStreaming} defaultExpanded={false}>
{reasoningContent}
</Think>;ThinkProps:
| Prop | Purpose |
|---|---|
title | Header text |
loading | Show loading indicator (boolean or custom node) |
expanded / defaultExpanded / onExpand | Controlled/uncontrolled expand |
blink | Animated blink while streaming |
children | Body content |
icon | Custom icon |
---
Actions
Purpose: Feedback/control buttons below an AI message — copy, thumbs up/down, retry, audio.
import { Actions } from '@ant-design/x';
<Actions
items={[
{
key: 'copy',
actionRender: () => <Actions.Copy text={messageContent} />,
},
{
key: 'feedback',
actionRender: () => <Actions.Feedback value={feedbackValue} onChange={setFeedbackValue} />,
},
{
key: 'retry',
icon: <RedoOutlined />,
label: 'Retry',
onItemClick: () => handleRetry(),
},
{
key: 'more',
icon: <MoreOutlined />,
subItems: [
{ key: 'edit', label: 'Edit' },
{ key: 'delete', label: 'Delete', danger: true },
],
},
]}
variant="borderless"
/>;Built-in sub-components:
| Component | Purpose |
|---|---|
Actions.Copy | Copy-to-clipboard button — prop text |
Actions.Feedback | Like/dislike toggle — props value, onChange |
Actions.Audio | Play/loading/error audio button — prop status |
Actions.Item | Generic item with status, label |
ActionsProps:
| Prop | Purpose |
|---|---|
items | Array of action items |
onClick | Global click handler |
variant | 'borderless' (default) \ |
fadeIn / fadeInLeft | Entrance animation |
---
Attachments
Purpose: File attachment list with drag-drop, paste, and overflow support — used in Sender.Header.
import { Attachments } from '@ant-design/x';
import { useState, useRef } from 'react';
const [fileList, setFileList] = useState([]);
const attachRef = useRef(null);
<Attachments
ref={attachRef}
items={fileList}
onChange={({ fileList: newList }) => setFileList(newList)}
overflow="scrollX"
placeholder={{
icon: <PaperClipOutlined />,
title: 'Drop files here',
description: 'Or click to browse',
}}
/>;
// Programmatically open file picker:
attachRef.current?.select({ accept: 'image/*', multiple: true });AttachmentsProps: Extends antd Upload props, key additions:
| Prop | Purpose |
|---|---|
items | Controlled file list (same as Upload fileList) |
overflow | 'wrap' \ |
placeholder | Shown when list is empty |
getDropContainer | Configure drop zone element |
maxCount | Max files |
---
Sources
Purpose: Show reference citations (URLs) used in an AI answer.
import { Sources } from '@ant-design/x';
<Sources
title="References"
items={[
{ key: '1', title: 'React Docs', url: 'https://react.dev', description: 'Official docs' },
{ key: '2', title: 'MDN', url: 'https://developer.mozilla.org' },
]}
defaultExpanded
onClick={(item) => window.open(item.url)}
/>;SourcesProps:
| Prop | Purpose |
|---|---|
items | Array of SourcesItem — key, title, url, icon, description |
title | Section heading |
expanded / defaultExpanded / onExpand | Controlled expand |
inline | Compact inline mode with popover |
onClick | Callback when source is clicked |
expandIconPosition | 'start' (default) \ |
---
Suggestion
Purpose: Slash-command or trigger-based suggestion popup in the Sender.
import { Suggestion, Sender } from '@ant-design/x';
<Suggestion
items={[
{ value: '/search', label: '/search', icon: <SearchOutlined /> },
{ value: '/help', label: '/help', icon: <QuestionOutlined /> },
]}
onSelect={(value) => console.log('Selected:', value)}
>
{({ onTrigger, onKeyDown }) => (
<Sender
onChange={(v) => {
if (v === '/') onTrigger({});
else onTrigger(false);
}}
onKeyDown={onKeyDown}
/>
)}
</Suggestion>;SuggestionProps:
| Prop | Purpose |
|---|---|
items | Array of SuggestionItem or render function (info) => SuggestionItem[] |
children | Render prop — ({ onTrigger, onKeyDown }) => ReactElement |
onSelect | Called with selected value and options path |
open / onOpenChange | Controlled panel visibility |
block | Full-width mode |
---
FileCard
Purpose: Display a file attachment card in a bubble (sent/received file).
import { FileCard } from '@ant-design/x';
<FileCard
item={{
uid: '1',
name: 'report.pdf',
size: 1024000,
status: 'done',
url: '/files/report.pdf',
}}
/>
// List of file cards
<FileCard.List items={fileItems} />---
CodeHighlighter
Purpose: Syntax-highlighted code block in a bubble or message.
import { CodeHighlighter } from '@ant-design/x';
<CodeHighlighter language="typescript" content={`const x = 1;`} />;Tip: When rendering code from Markdown, prefer @ant-design/x-markdown with a custom code block component mapping.---
Mermaid
Purpose: Render Mermaid diagrams inside chat messages.
import { Mermaid } from '@ant-design/x';
<Mermaid
content={`graph TD
A --> B
B --> C`}
/>;Tip: Use insideBubblecontentRenderor as a Markdown code block component forlanguage="mermaid".
---
Folder
Purpose: Display a hierarchical file/folder tree with optional file preview — useful in AI coding assistant scenarios.
import { Folder } from '@ant-design/x';
<Folder
treeData={[
{
title: 'src',
path: 'src',
children: [
{ title: 'index.tsx', path: 'src/index.tsx', content: 'export default () => null;' },
{ title: 'App.tsx', path: 'src/App.tsx', content: 'const App = () => <div />;' },
],
},
]}
defaultExpandAll
onSelectedFileChange={(file) => console.log(file.path, file.content)}
/>;Dynamic content loading via service:
<Folder
treeData={treeData}
fileContentService={{
loadFileContent: async (filePath) => {
const res = await fetch(`/api/file?path=${filePath}`);
return res.text();
},
}}
/>Key props:
| Prop | Purpose |
|---|---|
treeData | Tree structure — FolderTreeData[] with title, path, content, children |
selectedFile / defaultSelectedFile | Controlled/uncontrolled selected file paths |
onSelectedFileChange | Called with { path, name, content } on file select |
expandedPaths / defaultExpandedPaths | Controlled/uncontrolled expanded paths |
defaultExpandAll | Expand all nodes by default (true) |
fileContentService | Async service for loading file content on demand |
previewRender | Custom file preview renderer |
directoryTitle | Title above the tree (false to hide) |
directoryIcons | Custom icons per file type (false to hide all icons) |
selectable | Enable file selection (true by default) |
emptyRender | Empty state content |
---
XProvider
Purpose: Global configuration wrapper — replaces antd's ConfigProvider.
import { XProvider } from '@ant-design/x';
import zhCN from 'antd/locale/zh_CN';
import zhCN_X from '@ant-design/x/locale/zh_CN';
<XProvider
locale={{ ...zhCN, ...zhCN_X }}
theme={{
token: { colorPrimary: '#1677ff' },
}}
direction="ltr"
>
<App />
</XProvider>;- Fully extends
antd'sConfigProvider— all antd config props are valid. - Adds x-specific locale strings via
@ant-design/x/locale/zh_CN(oren_US). - Place once at the app root — do not nest multiple
XProviderinstances unnecessarily.
---
Notification
Purpose: Imperative notification messages (non-bubble, global alerts).
import { notification } from '@ant-design/x';
notification.open({
title: 'Connection lost',
description: 'Reconnecting...',
type: 'error',
});Use when you need to surface errors or events outside the chat bubble flow.
Composition Patterns
Pattern 1: Full Chat Page
The standard layout for an AI chat application.
import React, { useState } from 'react';
import {
XProvider,
Bubble,
Sender,
Conversations,
Welcome,
Prompts,
Actions,
ThoughtChain,
Think,
} from '@ant-design/x';
import { RobotOutlined, UserOutlined } from '@ant-design/icons';
import { Avatar, Flex } from 'antd';
// Role config — keep STABLE (define outside component or useMemo)
const roles = {
assistant: {
placement: 'start' as const,
avatar: <Avatar icon={<RobotOutlined />} />,
},
user: {
placement: 'end' as const,
avatar: <Avatar icon={<UserOutlined />} />,
},
};
export default function ChatPage() {
const [messages, setMessages] = useState([]);
const [conversations, setConversations] = useState([]);
const [activeKey, setActiveKey] = useState('1');
const [value, setSenderValue] = useState('');
const [loading, setLoading] = useState(false);
const isEmpty = messages.length === 0;
return (
<XProvider>
<Flex style={{ height: '100vh' }}>
{/* Sidebar */}
<Conversations
style={{ width: 240, borderRight: '1px solid #f0f0f0' }}
items={conversations}
activeKey={activeKey}
onActiveChange={setActiveKey}
groupable
creation={{ label: 'New Chat', onClick: () => {} }}
/>
{/* Main area */}
<Flex vertical flex={1} style={{ overflow: 'hidden' }}>
{/* Welcome screen or bubble list */}
{isEmpty ? (
<Flex vertical flex={1} align="center" justify="center" gap={16}>
<Welcome
title="Hello! How can I help?"
description="Choose a suggestion or type your own question."
variant="borderless"
/>
<Prompts
items={[
{ key: '1', label: 'Explain quantum computing' },
{ key: '2', label: 'Write a Python script' },
]}
wrap
onItemClick={(info) => {
setSenderValue(info.data.label as string);
}}
/>
</Flex>
) : (
<Bubble.List
style={{ flex: 1, overflow: 'auto', padding: 16 }}
items={messages}
role={roles}
autoScroll
/>
)}
{/* Input */}
<Sender
style={{ padding: 16 }}
value={value}
loading={loading}
onChange={setSenderValue}
onSubmit={(msg) => {
setSenderValue('');
setLoading(true);
// dispatch to data layer (use-x-chat or custom)
}}
onCancel={() => setLoading(false)}
/>
</Flex>
</Flex>
</XProvider>
);
}---
Pattern 2: Bubble with Message Actions
Add copy, feedback, and retry below each assistant message.
// Define items OUTSIDE render to keep them stable
const makeActionItems = (content: string, onRetry: () => void) => [
{
key: 'copy',
actionRender: () => <Actions.Copy text={content} />,
},
{
key: 'feedback',
actionRender: () => {
const [val, setVal] = React.useState<'like' | 'dislike' | 'default'>('default');
return <Actions.Feedback value={val} onChange={setVal} />;
},
},
{
key: 'retry',
label: 'Retry',
icon: <RedoOutlined />,
onItemClick: onRetry,
},
];
// In roles config:
const roles = {
assistant: {
placement: 'start',
footer: (content) => (
<Actions
items={makeActionItems(content as string, handleRetry)}
variant="borderless"
fadeIn
/>
),
},
};---
Pattern 3: Streaming Bubble
Connect Bubble.List to a streaming data source.
// With useXChat (from x-sdk):
import { useXChat } from '@ant-design/x-sdk';
const { parsedMessages, onRequest, isRequesting, abort } = useXChat({ provider });
// Map to Bubble.List items
const bubbleItems = parsedMessages.map((msg) => ({
key: msg.id,
role: msg.status === 'loading' ? 'assistant' : msg.role,
content: msg.message.content,
// streaming is true only while message is being generated
streaming: msg.status === 'loading',
loading: msg.status === 'loading' && !msg.message.content,
}));
<Bubble.List items={bubbleItems} role={roles} autoScroll />
<Sender
loading={isRequesting}
onSubmit={(msg) => onRequest({ message: { role: 'user', content: msg } })}
onCancel={abort}
/>---
Pattern 4: Reasoning / Thinking Display
Show a model's chain-of-thought before the final answer.
// Single collapsible think block
const roles = {
assistant: {
placement: 'start',
contentRender: (content, info) => {
const { reasoning, answer } = content as { reasoning: string; answer: string };
return (
<>
{reasoning && (
<Think
title="Thinking..."
loading={info.status === 'loading'}
blink={info.status === 'loading'}
defaultExpanded={false}
>
{reasoning}
</Think>
)}
<div>{answer}</div>
</>
);
},
},
};
// Multi-step tool call chain
<ThoughtChain
items={agentSteps.map((step) => ({
key: step.id,
title: step.toolName,
description: step.input,
status: step.status, // 'loading' | 'success' | 'error'
content: step.result,
collapsible: true,
blink: step.status === 'loading',
}))}
/>;---
Pattern 5: File Attachments in Sender
Allow users to attach files to their messages.
import { Sender, Attachments } from '@ant-design/x';
import { PaperClipOutlined } from '@ant-design/icons';
import { useState } from 'react';
const [fileList, setFileList] = useState([]);
const attachRef = useRef(null);
<Sender
prefix={<PaperClipOutlined onClick={() => attachRef.current?.select({ multiple: true })} />}
header={
fileList.length > 0 && (
<Sender.Header>
<Attachments
ref={attachRef}
items={fileList}
onChange={({ fileList: fl }) => setFileList(fl)}
overflow="scrollX"
/>
</Sender.Header>
)
}
onSubmit={(msg) => {
const payload = { message: msg, files: fileList };
setFileList([]);
handleSend(payload);
}}
/>;---
Pattern 6: Suggestion / Slash Commands
Trigger a suggestion popup when user types /.
import { Suggestion, Sender } from '@ant-design/x';
const commands = [
{ value: '/search', label: '/search — Search the web', icon: <SearchOutlined /> },
{ value: '/summarize', label: '/summarize — Summarize text', icon: <FileOutlined /> },
{ value: '/code', label: '/code — Generate code', icon: <CodeOutlined /> },
];
<Suggestion items={commands} onSelect={(val) => setValue(val + ' ')}>
{({ onTrigger, onKeyDown }) => (
<Sender
value={value}
onChange={(v) => {
setValue(v);
// Trigger suggestion on '/'
if (v.endsWith('/')) {
onTrigger({});
} else {
onTrigger(false);
}
}}
onKeyDown={onKeyDown}
onSubmit={handleSubmit}
/>
)}
</Suggestion>;---
Pattern 7: Source Citations
Show which documents were referenced in an AI answer.
const roles = {
assistant: {
placement: 'start',
footer: (content, info) => {
if (!info.sources?.length) return null;
return (
<Sources
title="Sources"
items={info.sources.map((s, i) => ({
key: String(i),
title: s.title,
url: s.url,
description: s.snippet,
}))}
defaultExpanded={false}
onClick={(item) => window.open(item.url, '_blank')}
/>
);
},
},
};---
Anti-patterns to Avoid
| Anti-pattern | Why it's wrong | Fix |
|---|---|---|
Mapping Bubble in a loop | Loses scroll anchoring, auto-scroll | Use Bubble.List |
Inline roles object in JSX | Re-creates object every render, resets animations | Define outside component or useMemo |
Leaving streaming={true} after stream ends | Incomplete content shown forever | Set streaming={false} on final chunk |
Putting raw HTML in content | XSS risk, no sanitization | Use contentRender with XMarkdown |
Multiple XProvider wraps | Theme/locale conflicts | Single root XProvider only |
Using onChange as submit handler | Fires on every keystroke | Use onSubmit for send action |
Related skills
FAQ
Do I use Bubble or Bubble.List in a loop?
Use Bubble.List, not Bubble, in loops; Bubble.List handles scroll anchoring, auto-scroll, and role-based layout that manual mapping loses.
What replaces antd's ConfigProvider?
Wrap the app root with XProvider, which supersedes antd's ConfigProvider and enables locale, direction, and x-specific shortcut keys.