import { useEffect } from "react";
import { useCreateChatClient } from "stream-chat";
const App = () => {
const chatClient = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: { id: userId },
});
useEffect(() => {
if (!chatClient) return;
chatClient.setMessageComposerSetupFunction(({ composer }) => {
composer.updateConfig({
linkPreviews: {
enabled: true,
},
});
});
}, [chatClient]);
return null;
};This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13)
.
Link Previews in Message Input
Link previews in MessageInput give users a visual hint of what will render later in the message list via the attachment card UI.
Best Practices
- Enable link previews only when they improve the compose experience for your users.
- Keep custom preview rendering lightweight and easy to dismiss.
- Prefer
MessageComposerconfiguration for behavior changes such as enablement, URL detection, and debounce timing. - Use
WithComponentsfor shared UI overrides instead of patchingChannel. - Test failed and loading states so the composer stays stable when enrichment is slow.
Enable Link Previews
Link previews are controlled through MessageComposer configuration:
The default MessageInputFlat renders LinkPreviewList inside the composer preview stack. By default it shows one loaded or loading preview at a time.
Customize The Link Preview UI
To replace the shared preview list UI, register a custom LinkPreviewList with WithComponents:
import { LinkPreviewsManager } from "stream-chat";
import {
Channel,
LinkPreviewCard,
MessageInput,
MessageList,
WithComponents,
useMessageComposer,
useStateStore,
} from "stream-chat-react";
const selectLinkPreviews = (state) => ({
linkPreviews: Array.from(state.previews.values()).filter(
(preview) =>
LinkPreviewsManager.previewIsLoaded(preview) ||
LinkPreviewsManager.previewIsLoading(preview),
),
});
const CustomLinkPreviewList = () => {
const { linkPreviewsManager } = useMessageComposer();
const { linkPreviews } = useStateStore(
linkPreviewsManager.state,
selectLinkPreviews,
);
if (!linkPreviews.length) return null;
return (
<div className="custom-link-preview-list">
{linkPreviews.map((linkPreview) => (
<LinkPreviewCard
key={linkPreview.og_scrape_url}
linkPreview={linkPreview}
/>
))}
</div>
);
};
const App = () => (
<WithComponents overrides={{ LinkPreviewList: CustomLinkPreviewList }}>
<Channel>
<MessageList />
<MessageInput />
</Channel>
</WithComponents>
);Change How Many Previews Are Visible
If you only need a different visible count, wrap the default LinkPreviewList and pass displayLinkCount:
import {
Channel,
LinkPreviewList,
MessageInput,
WithComponents,
} from "stream-chat-react";
const MultiPreviewLinkPreviewList = () => (
<LinkPreviewList displayLinkCount={3} />
);
const App = () => (
<WithComponents overrides={{ LinkPreviewList: MultiPreviewLinkPreviewList }}>
<Channel>
<MessageInput />
</Channel>
</WithComponents>
);Behavior Customization
You can customize URL discovery and enrichment behavior through MessageComposer configuration:
import { useEffect } from "react";
import type { LinkPreview } from "stream-chat";
import { useCreateChatClient } from "stream-chat";
import { customUrlDetector } from "./urlDetection";
const App = () => {
const chatClient = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: { id: userId },
});
useEffect(() => {
if (!chatClient) return;
chatClient.setMessageComposerSetupFunction(({ composer }) => {
composer.updateConfig({
linkPreviews: {
debounceURLEnrichmentMs: 2000,
enabled: true,
findURLFn: customUrlDetector,
onLinkPreviewDismissed: (linkPreview: LinkPreview) => {
chatClient.notifications.addInfo({
message: `Dismissed ${linkPreview.og_scrape_url}`,
origin: { emitter: composer.linkPreviewsManager },
});
},
},
});
});
}, [chatClient]);
return null;
};