reaction_overlay 0.1.0
reaction_overlay: ^0.1.0 copied to clipboard
A floating reaction bar (like iMessage/WhatsApp) for Flutter. Wrap any widget to add emoji reactions with animations, haptic feedback, dark mode, and smart positioning.
Reaction Overlay #
A floating reaction bar for Flutter, inspired by WhatsApp and iMessage. It anchors to any widget and provides quick reactions, an emoji picker, adaptive positioning, accessibility, and light/dark theme support.
Installation #
dependencies:
reaction_overlay: ^0.1.0
import 'package:reaction_overlay/reaction_overlay.dart';
Quick start #
Wrap a message, or any widget, with ReactionTarget. Long press it to open the reaction bar.
ReactionTarget(
reactions: [
Reaction('👍', label: 'Like', onTap: () => saveReaction('👍')),
Reaction('❤️', label: 'Love', onTap: () => saveReaction('❤️')),
Reaction('😂', label: 'Funny', onTap: () => saveReaction('😂')),
],
child: const MessageBubble(text: 'Hello'),
)
ReactionTarget does not require a GlobalKey: it uses the widget's BuildContext to calculate its position.
WhatsApp-style double tap and full bar #
Set quickReactionIndex to react immediately on double tap. Long press still opens the full reaction picker.
ReactionTarget(
reactions: ReactionSet.standard.reactions,
quickReactionIndex: 0, // 👍
onReactionChanged: (index, reaction) {
saveReaction(reaction.emoji!);
},
child: MessageBubble(text: message.text),
)
If you do not set quickReactionIndex, TriggerMode.doubleTap opens the full reaction bar instead.
Centralized configuration #
Use ReactionOverlayConfig when you reuse the same configuration or want to keep ReactionOverlay.show calls readable.
final messageReactions = ReactionOverlayConfig(
reactions: ReactionSet.social.reactions,
position: OverlayPosition.auto,
maxVisibleButtons: 6,
dimBackground: true,
showExpandButton: true,
recentEmojis: const ['👍', '❤️', '🙏'],
enableDragPreview: true,
enableSelectionParticles: false,
);
ReactionOverlay.show(
context: context,
config: messageReactions,
onReactionChanged: (index, reaction) {
saveReaction(reaction.emoji!);
},
onDismissed: () => debugPrint('Reaction picker closed'),
);
Do not mix config with individual styling parameters in ReactionOverlay.show; use the centralized configuration as the source of truth for those values. Callbacks passed to the method (onDismissed, onReactionChanged, and onEmojiSelected) can be supplied normally.
Common configuration options #
| Option | Default | Purpose |
|---|---|---|
reactions |
required | The list of Reaction objects shown in the bar. |
position |
OverlayPosition.auto |
Position: auto, above, below, left, or right. |
maxVisibleButtons |
6 |
Maximum before horizontal navigation appears. |
showExpandButton |
true |
Opens the full emoji panel. |
recentEmojis |
[] |
Emojis shown first in the full panel. |
dimBackground / dimColor |
true / 20% black |
Controls the background behind the bar. |
enableDragPreview |
true |
Magnifies the reaction under the finger while dragging. |
enableSelectionParticles |
true |
Shows particles on selection; disable for a quieter style. |
allowMultipleSelections |
false |
Keeps the picker open after a selection. |
Buttons keep a minimum 48×48 px tap target even if buttonSize or buttonHeight is smaller. The package also respects the system's reduce-motion preference.
Show the overlay manually #
Use ReactionOverlay.show when you provide your own gesture. The context must belong to a widget that has already been laid out.
GestureDetector(
onTap: () {
ReactionOverlay.show(
context: context,
reactions: [Reaction('👍'), Reaction('❤️')],
position: OverlayPosition.above,
onReactionChanged: (index, reaction) => saveReaction(reaction.emoji!),
);
},
child: const MessageBubble(text: 'Tap me'),
)
Custom reactions and presets #
final reactions = [
Reaction('👍', label: 'Like'),
Reaction.custom(
child: const Icon(Icons.star, color: Colors.amber),
label: 'Favorite',
),
];
// Presets: standard, social, work, gaming, and minimal.
final socialReactions = ReactionSet.social.reactions;
Global theme #
Configure visual values that apply to all ReactionTarget widgets.
MaterialApp(
theme: ThemeData(
extensions: const [
ReactionOverlayThemeData(
position: OverlayPosition.above,
enableHapticFeedback: true,
buttonSize: 44,
buttonHeight: 48,
),
],
),
home: const ChatPage(),
)
Properties passed directly to ReactionTarget take precedence over this theme.
Programmatic control #
ReactionOverlayController lets you inspect visibility and the most recently selected reaction.
final controller = ReactionOverlayController();
controller.show(
context: context,
reactions: ReactionSet.standard.reactions,
);
// controller.isVisible
// controller.selectedReaction
controller.dismiss();
// Call dispose when the controller is no longer needed.
controller.dispose();
Migrating from 0.0.3 #
Version 0.1.0 simplifies the API and removes manual key management.
| In 0.0.3 | In 0.1.0 |
|---|---|
AppReactionOverlayManager |
ReactionOverlay.show, ReactionTarget, or ReactionOverlayController. |
itemKey / itemId |
Remove these parameters; pass the BuildContext to ReactionOverlay.show or use ReactionTarget. |
List<IconButton> buttons |
List<Reaction> reactions. |
| Manually building the overlay | ReactionTarget for the usual case. |
1. Replace IconButton with Reaction #
Previously, reactions were built with IconButton widgets. Use the simpler model now:
// 0.0.3
final buttons = [
IconButton(icon: const Icon(Icons.thumb_up), onPressed: onLike),
];
// 0.1.0
final reactions = [
Reaction('👍', label: 'Like', onTap: onLike),
];
To keep a custom icon, use Reaction.custom:
Reaction.custom(
child: const Icon(Icons.thumb_up),
label: 'Like',
onTap: onLike,
)
2. Remove GlobalKey, itemKey, and itemId #
Instead of managing position through a key, wrap the content:
// 0.1.0
ReactionTarget(
reactions: reactions,
child: MessageBubble(text: message.text),
)
If you need to open the picker from your own gesture, call ReactionOverlay.show with that widget's context, as shown above.
3. Replace the manager #
Replace AppReactionOverlayManager with one of these options:
ReactionTarget: recommended declarative integration.ReactionOverlay.show: when you already have a gesture callback.ReactionOverlayController: when another part of your app needs to close, toggle, or observe the overlay.
Accessibility and interaction #
- Long press opens the reaction bar; quick double tap is optional.
- Left/right arrows navigate, Enter/Space selects, and Escape closes.
- Give every
Reactionalabelso screen readers announce a useful action. - Use
onReactionChangedto synchronize a selection with your backend.
Demo #
See the example directory for a demo application.