Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

ChatView | Acknowledgements

Acknowledgements are emoji reactions displayed as pill-shaped badges below a message bubble. Think of Slack reactions or iMessage tapbacks — users can react to messages with emojis, and the reactions are grouped and counted.

Acknowledgements are grouped by Glyph and displayed as badges:

  • Single reaction: Shows the glyph only — [👍]
  • Multiple same glyph: Shows glyph + count — [👍 3]
  • Multiple different glyphs: Separate badges — [👍 2] [❤️] [💯]

Badges appear in a horizontal row below the chat bubble with 4px spacing.

Each ChatMessage has an Acknowledgements list:

var message = new ChatMessage
{
Text = "The deployment is complete!",
SenderId = "bot",
IsFromMe = false,
Acknowledgements = new List<Acknowledgement>
{
new() { Glyph = "🎉", UserId = "alice", Timestamp = DateTime.Now },
new() { Glyph = "👍", UserId = "bob", Timestamp = DateTime.Now },
new() { Glyph = "👍", UserId = "charlie", Timestamp = DateTime.Now }
}
};
// Renders: [🎉] [👍 2]
PropertyTypeDescription
Glyphstring?The emoji or character (e.g., ”👍”, “❤️”, ”💯“)
UserIdstringID of the user who reacted
TimestampDateTimeWhen the reaction was added

Null or empty Glyph values are skipped during rendering.

Add reactions after the message is already displayed:

// Initialize if null
message.Acknowledgements ??= new List<Acknowledgement>();
// Add a reaction
message.Acknowledgements.Add(new Acknowledgement
{
Glyph = "❤️",
UserId = "currentUser",
Timestamp = DateTime.Now
});
var reaction = message.Acknowledgements?
.FirstOrDefault(a => a.UserId == currentUserId && a.Glyph == "👍");
if (reaction != null)
message.Acknowledgements.Remove(reaction);

A common UX pattern is tap-to-toggle: if the user already reacted with this emoji, remove it; otherwise add it.

void ToggleReaction(ChatMessage message, string glyph)
{
message.Acknowledgements ??= new List<Acknowledgement>();
var existing = message.Acknowledgements
.FirstOrDefault(a => a.UserId == myId && a.Glyph == glyph);
if (existing != null)
message.Acknowledgements.Remove(existing);
else
message.Acknowledgements.Add(new Acknowledgement
{
Glyph = glyph,
UserId = myId,
Timestamp = DateTime.Now
});
// Refresh UI (MAUI)
var index = Messages.IndexOf(message);
Messages.RemoveAt(index);
Messages.Insert(index, message);
}
hubConnection.On<string, string, string>("ReactionAdded", (messageId, userId, glyph) =>
{
var msg = Messages.FirstOrDefault(m => m.Id == messageId || m.Identifier == messageId);
if (msg == null) return;
msg.Acknowledgements ??= new List<Acknowledgement>();
msg.Acknowledgements.Add(new Acknowledgement
{
Glyph = glyph,
UserId = userId,
Timestamp = DateTime.Now
});
// Refresh
var index = Messages.IndexOf(msg);
Messages.RemoveAt(index);
Messages.Insert(index, msg);
});
async Task ReactToMessage(ChatMessage message, string glyph)
{
// Optimistically add locally
message.Acknowledgements ??= new List<Acknowledgement>();
message.Acknowledgements.Add(new Acknowledgement
{
Glyph = glyph,
UserId = myId,
Timestamp = DateTime.Now
});
var index = Messages.IndexOf(message);
Messages.RemoveAt(index);
Messages.Insert(index, message);
// Send to server
await hubConnection.SendAsync("AddReaction", message.Identifier, glyph);
}

A natural way to expose reactions is through bubble tools:

<shiny:ChatView.BubbleToolItems>
<shiny:FabMenuItem Text="👍" FabBackgroundColor="#FFC107"
Command="{Binding ThumbsUpCommand}" />
<shiny:FabMenuItem Text="❤️" FabBackgroundColor="#E91E63"
Command="{Binding HeartCommand}" />
<shiny:FabMenuItem Text="😂" FabBackgroundColor="#FF9800"
Command="{Binding LaughCommand}" />
</shiny:ChatView.BubbleToolItems>
[RelayCommand]
void ThumbsUp(ChatMessage message) => ToggleReaction(message, "👍");
[RelayCommand]
void Heart(ChatMessage message) => ToggleReaction(message, "❤️");
[RelayCommand]
void Laugh(ChatMessage message) => ToggleReaction(message, "😂");
AspectValue
Badge background#E5E7EB (light gray)
Badge corner radius10px
Glyph font size12pt
Count font size11pt
Badge spacing4px between badges
PositionBelow the bubble, above the timestamp

Badges render on both “my” and “other” messages. They appear regardless of IsMultiPerson setting.