Chat Avatar Rendering#
Dify's chat UI uses four distinct avatar components, each serving a different surface. Understanding which component to use β and how the icon-type resolution works β is the key to working in this area.
Component Map#
| Component | Path | Renders |
|---|---|---|
AnswerIcon | base/answer-icon/index.tsx | Bot reply avatar in chat thread |
AppIcon | base/app-icon/index.tsx | App icon across the product (lists, headers, etc.) |
WorkspaceAvatar | base/workspace-avatar/index.tsx | Workspace identity in nav & member settings |
LogoEmbeddedChatAvatar | base/logo/logo-embedded-chat-avatar.tsx | Static logo in the embedded chatbot widget |
Rendering Priority & Fallback Logic#
Both AnswerIcon and AppIcon follow the same three-tier priority :
- Image URL β when
iconType === 'image'andimageUrlis present, renders an<img>tag filling the container. - Emoji β when
iconis a non-empty string, resolves it via the sharedresolveEmojicompatibility map and renders the resulting Unicode character. - Robot fallback β renders
π€when neither condition is met.
The AppIconType type (from @/types/app) discriminates between 'image' and emoji icon modes.
Key Components#
AnswerIcon#
AnswerIcon is a lightweight component specifically for the bot-side avatar in a chat message. It always renders as a full-width/height circle (rounded-full). The background defaults to #D5F5F6 if no background prop is provided . Props: iconType, icon, background, imageUrl.
Emojis are resolved synchronously via resolveEmoji from @/utils/emoji, which preserves 1,870 persisted emoji IDs and 61 aliases from the previous emoji-mart library alongside Unicode, image icons, and fallback icons.
AppIcon#
AppIcon is the general-purpose icon for apps and datasets. It adds:
- Size variants (
xsβxxl) viacva. - Rounded prop to toggle
rounded-fullvs. the size's default border radius. - Emoji resolution β uses the same synchronous
resolveEmojimap asAnswerIcon, so emojis render consistently on both server and client without hydration mismatches. - Edit overlay β
showEditIconprop activates a hover overlay withRiEditLine. - Default background:
#FFEAD5.
WorkspaceAvatar#
WorkspaceAvatar renders a square initial-based avatar (no image or emoji support). It displays the first character of the workspace name in uppercase, or '?' as fallback . Built on AvatarRoot/AvatarFallback from @langgenius/dify-ui. Supported sizes: xs | sm | lg | 2xl . This component was introduced to unify previously inconsistent workspace avatar rendering across navigation and Members settings .
LogoEmbeddedChatAvatar#
LogoEmbeddedChatAvatar is a static <img> pointing to ${basePath}/logo/logo-embedded-chat-avatar.png β a fixed asset, not app-configurable. Used at the top of the embedded chatbot widget.
Chat Thread Integration#
In Answer, the avatar container is a size-10 div. It renders the answerIcon prop if provided; otherwise falls back to <AnswerIcon /> with no props (pure robot emoji). Callers (e.g., the full chat page or embedded chatbot) are responsible for constructing an <AnswerIcon iconType={...} icon={...} imageUrl={...} /> element and passing it as answerIcon.
The top-level Chat component exposes both questionIcon and answerIcon as ReactNode props, letting callers supply any icon shape for either side of the conversation.
Emoji Resolution & Picker#
Both AppIcon and AnswerIcon share a synchronous emoji resolver (resolveEmoji in @/utils/emoji) that preserves 1,870 persisted emoji IDs and 61 aliases from the previous emoji-mart library. This compatibility map allows existing icons to render without requiring client-side initialization or Web Components. New emoji selections made through the picker emit Unicode directly.
The emoji picker itself is built with Frimousse and uses versioned, self-hosted Emojibase data served from public/emoji/emojibase-17.0.0. English emoji metadata (data and category messages) is dynamically imported in a separate chunk. No runtime CDN is required; all emoji data is served as local static assets that respect the deployment base path.