# Reactions

Reactions

### Overview

The reactions system in v10 (design-refresh) introduces a new set of components for displaying, picking, and listing reactions. The key components are:

- `StreamMessageReactionPicker` — the quick-pick reaction bar
- `ReactionDetailSheet` — a bottom sheet showing full reaction details
- `StreamReactionListView` + `StreamReactionListController` — paginated list of reactors
- `ReactionIconResolver` — abstract contract for customizing reaction icons/emoji

### StreamMessageReactionPicker

`StreamMessageReactionPicker` (previously `StreamReactionPicker`) displays the quick-pick reaction bar. The available reactions come from `StreamChatConfigurationData.reactionIconResolver.defaultReactions`.

```dart
StreamMessageReactionPicker(
  message: message,
  onReactionPicked: (reactionType) => _addReaction(reactionType),
)
```

Visual customization is done via `StreamReactionPickerTheme`:

```dart
StreamReactionPickerTheme(
  data: StreamReactionPickerThemeData(
    backgroundColor: Colors.white,
    elevation: 4,
    spacing: 2,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(24)),
    ),
  ),
  child: ...,
)
```

### ReactionIconResolver

`ReactionIconResolver` is an abstract contract for mapping reaction types to emoji or widgets. Extend `DefaultReactionIconResolver` and override only what you need:

```dart
class MyReactionIconResolver extends DefaultReactionIconResolver {
  const MyReactionIconResolver();

  // Which reactions appear in the quick-pick bar
  @override
  Set<String> get defaultReactions => const {'like', 'love', 'haha', 'wow', 'sad'};

  // Return a Unicode emoji for a reaction type, or null for fallback
  @override
  String? emojiCode(String type) {
    if (type == 'celebrate') return '🎉';
    return super.emojiCode(type); // delegates to streamSupportedEmojis map
  }
}
```

Register the resolver globally:

```dart
StreamChat(
  client: client,
  streamChatConfigData: StreamChatConfigurationData(
    reactionIconResolver: const MyReactionIconResolver(),
  ),
  child: ...,
)
```

**Custom rendering (e.g. Twemoji images):**

```dart
class MyReactionIconResolver extends DefaultReactionIconResolver {
  const MyReactionIconResolver();

  @override
  Widget resolve(BuildContext context, String type) {
    switch (type) {
      case 'love':
        return MyTwemojiWidget(assetName: 'heart');
      case 'haha':
        return MyTwemojiWidget(assetName: 'joy');
      default:
        return super.resolve(context, type);
    }
  }
}
```

### ReactionDetailSheet

`ReactionDetailSheet` replaces `MessageReactionsModal`. It shows a draggable bottom sheet with:

- Total reaction count
- Filter chips per reaction type
- Paginated list of users who reacted

Use the static `show` method — the constructor is private:

```dart
final action = await ReactionDetailSheet.show(
  context: context,
  message: message,
  initialReactionType: 'like', // optional: pre-select a type
);

if (action is SelectReaction) {
  _handleReactionSelected(action.reaction);
}
```

`show` returns `MessageAction?`:

- `SelectReaction` — user picked or removed a reaction
- `null` — sheet dismissed without selection

### StreamReactionListController

`StreamReactionListController` loads and paginates reactions for a message. It extends `PagedValueNotifier<String?, Reaction>`.

```dart
final controller = StreamReactionListController(
  client: StreamChat.of(context).client,
  messageId: message.id,
  sort: const [SortOption.desc(ReactionSortKey.createdAt)],
  limit: 25,
);

await controller.doInitialLoad();
```

Filter reactions by type at runtime (e.g. when user taps a filter chip):

```dart
controller.filter = Filter.equal('type', 'like');
controller.doInitialLoad();
```

### StreamReactionListView

`StreamReactionListView` renders a paginated list of reactions using a `StreamReactionListController`:

```dart
StreamReactionListView(
  controller: controller,
  itemBuilder: (context, reactions, index) {
    final reaction = reactions[index];
    return ListTile(
      leading: Text(reaction.type),
      title: Text(reaction.user?.name ?? ''),
    );
  },
  emptyBuilder: (_) => const Center(child: Text('No reactions yet')),
)
```

| Parameter              | Required | Description                                               |
| ---------------------- | -------- | --------------------------------------------------------- |
| `controller`           | yes      | Provides and paginates reaction data                      |
| `itemBuilder`          | yes      | Builds each reaction item                                 |
| `separatorBuilder`     | no       | Builds separators between items                           |
| `emptyBuilder`         | no       | Widget shown when there are no reactions                  |
| `loadingBuilder`       | no       | Widget shown during initial load                          |
| `errorBuilder`         | no       | Widget shown on error                                     |
| `loadMoreTriggerIndex` | no       | How many items from end to trigger next page (default: 3) |


---

This page was last updated at 2026-04-23T18:43:03.613Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/flutter/v10/stream_chat_flutter/reactions/](https://getstream.io/chat/docs/sdk/flutter/v10/stream_chat_flutter/reactions/).