import {
WithComponents,
Channel,
MessageList,
MessageComposer,
ChannelList,
type IconComponent,
} from "stream-chat-react";
import { clsx } from "clsx";
// SDK may pass props to your icon component, adjust your defaults and spread the rest (SVG only)
const CustomMuteIcon: IconComponent = ({ className, ...rest }) => (
<svg
viewBox="0 0 20 20"
className={clsx("str-chat__icon", className)}
{...rest}
>
<path
d="M3 3l18 18M9 9v6a3 3 0 004.5 2.6M12 4a3 3 0 013 3v3"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
/>
</svg>
);
<WithComponents overrides={{ icons: { IconMute: CustomMuteIcon } }}>
<ChannelList />
<Channel>
<MessageList />
<MessageComposer />
</Channel>
</WithComponents>;Custom Icons
Every icon the SDK renders — the send arrow, delivery checkmarks, the mute and pin badges, the attachment-picker glyphs, and more — can be replaced with your own. Icons are exposed through the same WithComponents provider used for other UI components, grouped under a single icons key.
Best Practices
- Override icons with
WithComponentsunder theiconskey — you only need to provide the icons you want to change. - Have custom icons match
IconComponentinterface and honor the expected defaults used in default SDK icons (viewBoxse to0 0 20 20andfill/stroketo eithernoneorcurrentColor) if your custom component returns an SVG. - Preserve
classNameproperty coming from the SDK and reusestr-chat__iconclass for easier styling adjustments. - Set app-wide icon overrides high in the tree (around
Chat), and override more specifically deeper down only when needed. - Keep custom icons lightweight — the same icon may render once per message row inside
MessageList.
Overriding an icon
Pass an icons object to the overrides prop of WithComponents. Each key is the name of an SDK icon, and the value is your replacement component. Only the icons you list are replaced — every other icon keeps its default.
Your icon is now used everywhere the SDK renders the mute icon within that subtree — for example, in the channel list preview and channel details.
Overriding multiple icons
Add as many entries as you need. Sibling defaults are preserved, so this replaces only the send and reply icons:
<WithComponents
overrides={{
icons: {
IconSend: CustomSendIcon,
IconReply: CustomReplyIcon,
},
}}
>
<Channel channel={channel}>
<MessageList />
<MessageComposer />
</Channel>
</WithComponents>Icon overrides are merged per-icon: providing icons={{ IconMute: CustomMuteIcon }} swaps the mute icon while leaving all other icons at their defaults. You never have to supply the full icon set.
Using any component as an icon
A custom icon is just a React component that accepts SVG props. It doesn't have to be an SVG — you can render an image, a component from another icon library, or anything else.
import {
WithComponents,
Channel,
MessageList,
MessageComposer,
type IconComponent,
} from "stream-chat-react";
import { clsx } from "clsx";
const ImageSendIcon: IconComponent = ({ className }) => (
<image
src="path/to/image.jpg"
className={clsx("str-chat__icon", className)}
/>
);
<WithComponents overrides={{ icons: { SendRight: ImageSendIcon } }}>
<Channel channel={channel}>
<MessageList />
<MessageComposer />
</Channel>
</WithComponents>;How icon props work
Every SDK icon accepts props based on an IconComponent interface that looks like this:
import type { ComponentPropsWithoutRef, ComponentType } from "react";
export type IconComponent = ComponentType<ComponentPropsWithoutRef<"svg">>;When the SDK renders an icon it may pass some additional properties (like a specific className or SVG overrides) - these properties may shape the icon. Well-behaved custom icon should rely on the CSS properties of the parent elements (such as currentColor) or theming-related CSS variables.
Inheritance
Icon overrides follow the same inheritance rules as other WithComponents overrides. Inner providers merge over outer ones, so you can set app-wide icons at the top of the tree and override a specific icon deeper down:
// App-wide default icons
<WithComponents overrides={{ icons: { IconSend: BrandSendIcon } }}>
<Chat client={client}>
{/* This channel uses a different send icon; everything else inherits BrandSendIcon */}
<WithComponents overrides={{ icons: { IconSend: SpecialSendIcon } }}>
<Channel channel={channel}>
<MessageList />
<MessageComposer />
</Channel>
</WithComponents>
</Chat>
</WithComponents>Reading the resolved icons
Inside your own custom components you can read the resolved icon set — defaults merged with any overrides — from useComponentsContextIcons(). This lets a custom component reuse the same (possibly overridden) icons the SDK uses.
import { useComponentsContextIcons } from "stream-chat-react";
const CustomSendButton = () => {
const { IconSend } = useComponentsContextIcons();
return (
<div>
<IconSend />
</div>
);
};