This is beta documentation for Stream Chat Flutter SDK v10. For the latest stable version, see the latest version (v9).

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 the StreamComponentFactory and delegates rendering
  • StreamMessageWidgetProps — plain data class holding all configuration, supports copyWith()
  • DefaultStreamMessage — default rendering implementation, composes the sub-components below
  • StreamMessageContent — bubble, attachments, text, reactions, thread replies
  • StreamMessageFooter — username, timestamp, sending status, edited indicator
  • StreamMessageLeading — author avatar
  • StreamMessageReactions — clustered reaction chips around the bubble
  • StreamMessageText — 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:

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);
        },
      ),
    );
  }
}

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:

OldNew
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:

ParameterType
onEditMessageTapvoid Function(Message)?
onReplyTapvoid Function(Message)?
onUserAvatarTapvoid Function(User)?
onReactionsTapvoid Function(Message)?
onQuotedMessageTapvoid Function(Message)?
onMessageLinkTapvoid Function(Message, String)?
onUserMentionTapvoid 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 ParameterMigration Path
showReactionsStreamMessageItemThemeData visibility
showDeleteMessage / showEditMessageChannel permissions
showUsername / showTimestampStreamMessageItemThemeData.footerVisibility
showUserAvatarStreamMessageItemThemeData.leadingVisibility
userAvatarBuilderComponent factory (replace DefaultStreamMessage)
textBuilderComponent factory (replace StreamMessageContent)
customActionsactionsBuilder on StreamMessageWidgetProps
onCustomActionTaponTap per StreamContextMenuAction
reverseDetermined by StreamMessagePlacement context
messageThemeResolved from context automatically
shape, borderSide, borderRadiusGeometryStreamMessageBubble theming
copyWith() on StreamMessageWidgetStreamMessageWidgetProps.copyWith()