class ChannelPage extends StatelessWidget {
const ChannelPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamMessageListView(
messageBuilder: (context, message, defaultProps) {
// Build the default widget (goes through component factory)
return StreamMessageWidget.fromProps(props: defaultProps);
},
),
);
}
}StreamMessageWidget
A Widget For Displaying Messages And Attachments
Find the pub.dev documentation here
Background
StreamMessageWidget is a thin shell widget that renders a single message, including its attachments, reactions, sender avatar, timestamp, and other metadata.
In v10 (design-refresh), the widget was refactored from a monolithic ~50-parameter component into a clean architecture:
StreamMessageWidget— thin shell, resolves theStreamComponentFactoryand delegates renderingStreamMessageWidgetProps— plain data class holding all configuration, supportscopyWith()DefaultStreamMessage— default rendering implementation, composes the sub-components belowStreamMessageContent— bubble, attachments, text, reactions, thread repliesStreamMessageFooter— username, timestamp, sending status, edited indicatorStreamMessageLeading— author avatarStreamMessageReactions— clustered reaction chips around the bubbleStreamMessageText— markdown-rendered message text
Basic Example
The StreamMessageWidget is primarily used inside StreamMessageListView. Use the messageBuilder callback to customize individual messages. The callback now receives StreamMessageWidgetProps (raw configuration data) instead of a pre-built widget:
Customizing via copyWith
Use StreamMessageWidgetProps.copyWith() to customize specific properties:
StreamMessageListView(
messageBuilder: (context, message, defaultProps) {
return StreamMessageWidget.fromProps(
props: defaultProps.copyWith(
actionsBuilder: (context, defaultActions) => [
...defaultActions,
StreamContextMenuAction(
leading: const Icon(Icons.star),
label: const Text('Favourite'),
onTap: () => _favourite(message),
),
],
),
);
},
)New Callback Signatures
Several callbacks have been renamed or changed signature:
| Old | New |
|---|---|
onLinkTap: void Function(String url) | onMessageLinkTap: void Function(Message, String url) |
onMentionTap: void Function(User) | onUserMentionTap: void Function(User) |
onQuotedMessageTap: void Function(String?) | onQuotedMessageTap: void Function(Message) |
StreamMessageListView(
onMessageLinkTap: (message, url) => launchUrl(Uri.parse(url)),
onUserMentionTap: (user) => showProfile(user),
onQuotedMessageTap: (quotedMessage) => scrollToMessage(quotedMessage.id),
)New List-Level Callbacks
These callbacks can now be set at the list level and are forwarded to all messages:
| Parameter | Type |
|---|---|
onEditMessageTap | void Function(Message)? |
onReplyTap | void Function(Message)? |
onUserAvatarTap | void Function(User)? |
onReactionsTap | void Function(Message)? |
onQuotedMessageTap | void Function(Message)? |
onMessageLinkTap | void Function(Message, String)? |
onUserMentionTap | void Function(User)? |
Building Custom Attachments
Register custom attachment builders globally via StreamChatConfigurationData:
StreamChat(
client: client,
streamChatConfigData: StreamChatConfigurationData(
attachmentBuilders: [
LocationAttachmentBuilder(),
...defaultAttachmentBuilders,
],
),
child: ...,
)You can also override attachment builders per-message via StreamMessageWidgetProps.attachmentBuilders.
Swipeable Messages Example
StreamMessageListView(
messageBuilder: (context, message, defaultProps) {
final defaultWidget = StreamMessageWidget.fromProps(props: defaultProps);
if (message.isDeleted || message.state.isFailed) return defaultWidget;
final alignment = StreamMessagePlacement.alignmentDirectionalOf(context);
final isEnd = alignment == AlignmentDirectional.centerEnd;
return Swipeable(
key: ValueKey(message.id),
direction: isEnd ? SwipeDirection.endToStart : SwipeDirection.startToEnd,
swipeThreshold: 0.2,
onSwiped: (_) => onReply(message),
child: defaultWidget,
);
},
)Theming
Theme is now resolved automatically from context — no messageTheme parameter needed:
// Old (v9 and earlier)
StreamMessageWidget(
message: message,
messageTheme: isMyMessage
? streamTheme.ownMessageTheme
: streamTheme.otherMessageTheme,
)
// New
StreamMessageWidget(message: message)Use StreamMessageItemThemeData to control visibility and styling via the theme system:
StreamChatThemeData(
// Configure per-message item theming...
)Removed Parameters
Many parameters that existed on StreamMessageWidget have been removed. Here is the migration path:
| Removed Parameter | Migration Path |
|---|---|
showReactions | StreamMessageItemThemeData visibility |
showDeleteMessage / showEditMessage | Channel permissions |
showUsername / showTimestamp | StreamMessageItemThemeData.footerVisibility |
showUserAvatar | StreamMessageItemThemeData.leadingVisibility |
userAvatarBuilder | Component factory (replace DefaultStreamMessage) |
textBuilder | Component factory (replace StreamMessageContent) |
customActions | actionsBuilder on StreamMessageWidgetProps |
onCustomActionTap | onTap per StreamContextMenuAction |
reverse | Determined by StreamMessagePlacement context |
messageTheme | Resolved from context automatically |
shape, borderSide, borderRadiusGeometry | StreamMessageBubble theming |
copyWith() on StreamMessageWidget | StreamMessageWidgetProps.copyWith() |