# 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`](https://getstream.io/chat/docs/sdk/react/components/contexts/component-context/) provider used for other UI components, grouped under a single `icons` key.

## Best Practices

- Override icons with `WithComponents` under the `icons` key — you only need to provide the icons you want to change.
- Have custom icons match `IconComponent` interface and honor the expected defaults used in default SDK icons (`viewBox` se to `0 0 20 20` and `fill`/`stroke` to either `none` or `currentColor`) if your custom component returns an SVG.
- Preserve `className` property coming from the SDK and reuse `str-chat__icon` class 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.

```tsx
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>;
```

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:

```tsx
<WithComponents
  overrides={{
    icons: {
      IconSend: CustomSendIcon,
      IconReply: CustomReplyIcon,
    },
  }}
>
  <Channel channel={channel}>
    <MessageList />
    <MessageComposer />
  </Channel>
</WithComponents>
```

<Admonition type="info">

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.

</Admonition>

### 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.

```tsx
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:

```tsx
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:

```tsx
// 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.

```tsx
import { useComponentsContextIcons } from "stream-chat-react";

const CustomSendButton = () => {
  const { IconSend } = useComponentsContextIcons();

  return (
    <div>
      <IconSend />
    </div>
  );
};
```


---

This page was last updated at 2026-07-30T15:20:23.470Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/guides/custom-icons/](https://getstream.io/chat/docs/sdk/react/guides/custom-icons/).