Basic
MudChat can be used to display one or more MudChatBubble
components. The bubbles can be aligned at the start (left for Left-to-Right, right for Right-to-Left) or at the end.
<MudChat ChatPosition="ChatBubblePosition.Start"> <MudChatBubble> It's over Anakin </MudChatBubble> <MudChatBubble> I have the high ground. </MudChatBubble> </MudChat> <MudChat ChatPosition="ChatBubblePosition.End"> <MudChatBubble> You underestimate my power! </MudChatBubble> </MudChat>
With Avatar
MudChat can include an avatar, which works seamlessly with the MudAvatar
component. The avatar will always appear on the first MudChatBubble
inside a MudChat.

<MudChat ChatPosition="ChatBubblePosition.Start"> <MudAvatar>OK</MudAvatar> <MudChatBubble> It was said that you would, destroy the Sith, not join them. </MudChatBubble> <MudChatBubble> It was you who would bring balance to the Force </MudChatBubble> </MudChat> <MudChat ChatPosition="ChatBubblePosition.Start"> <MudAvatar> <MudImage Src="images/jonny.jpg" /> </MudAvatar> <MudChatBubble> Not leave it in Darkness </MudChatBubble> </MudChat>
<MudChat ChatPosition="ChatBubblePosition.Start"> <MudChatHeader Name="Obi-Wan Kenobi" Time="2 hours ago" /> <MudChatBubble>You were my brother Anakin.</MudChatBubble> <MudChatFooter Text="Seen" /> </MudChat> <MudChat ChatPosition="ChatBubblePosition.Start"> <MudChatHeader> <MudAlert Severity="Severity.Info" Dense="true">Obi-Wan Kenobi</MudAlert> </MudChatHeader> <MudChatBubble>I loved you.</MudChatBubble> <MudChatFooter> <MudAlert Severity="Severity.Info" Dense="true">Seen</MudAlert> </MudChatFooter> </MudChat>
ChatBubble OnClick Parameter
You can define the OnClick and/or OnContextClick parameter for the MudChatBubble
component to handle click events.
@inject ISnackbar Snackbar @{ var orderedGroups = messages .OrderByDescending(m => m.Time) .GroupBy(m => m.Name) .ToList(); for (int i = 0; i < orderedGroups.Count; i++) { var group = orderedGroups[i]; var position = i == 0 ? ChatBubblePosition.Start : ChatBubblePosition.End; <MudChat ChatPosition=""> <MudAvatar>@group.First().Initials</MudAvatar> <MudChatHeader Name="@group.Key" Time="@group.First().Time" /> @foreach (var message in group.OrderByDescending(m => m.Time)) { <MudChatBubble OnClick="(MouseEventArgs args) => ClickMessage(args, message)" OnContextClick="(MouseEventArgs args) => RightClickMessage(args, message)"> @message.Text </MudChatBubble> } </MudChat> } } <MudMenu PositionAtCursor="true" @ref="_contextMenu" id="_contextMenu"> <MudMenuItem Icon="@Icons.Material.Filled.Block" OnClick=""> Ban @_selectedMessage?.Name </MudMenuItem> <MudMenuItem Icon="@Icons.Material.Filled.Info" OnClick=""> View Details for @_selectedMessage?.Name </MudMenuItem> </MudMenu>
@code { #nullable enable private List<Message> messages = new(); private Message? _selectedMessage; private MudMenu? _contextMenu; protected override void OnInitialized() { messages.Add(new Message("Obi-Wan Kenobi", "OK", "You were my brother Anakin.", "2 hours ago")); messages.Add(new Message("Obi-Wan Kenobi", "OK", "I loved you.", "2 hours ago")); messages.Add(new Message("Anakin Skywalker", "AS", "I'm sorry.", "1 hour ago")); } private void ShowHiddenInfo() { if (_selectedMessage is not null) { Snackbar.Add($"Hidden information for {_selectedMessage.Name}", Severity.Info); } } private void BanUser() { if (_selectedMessage is not null) { Snackbar.Add($"{_selectedMessage.Name} has been banned!", Severity.Error); } } private async Task RightClickMessage(MouseEventArgs args, Message message) { _selectedMessage = message; if (_contextMenu != null) await _contextMenu.OpenMenuAsync(args); } private async Task ClickMessage(MouseEventArgs args, Message message) { _selectedMessage = message; Snackbar.Add("Message clicked: " + message.Text, Severity.Info); await Task.CompletedTask; } private record Message(string Name, string Initials, string Text, string Time); }
Additional Chat Bubble Options
MudChat
can be customized with the following properties:
Dense
: Reduces the vertical margins of the chat bubbles.Square
: Makes the chat bubbles square.Elevation
: The elevation of the chat bubbles. Defaults to 0.ArrowPosition
: The position of the arrow on the first chat bubble. Defaults to Top.- *
Color
: The color of the chat bubbles. Defaults toColor.Default
. - *
Variant
: The variant of the chat bubbles. Defaults toVariant.Text
.
MudChatBubble
components, and can be overridden individually.


To be on the Council at your age.
<MudGrid> <MudItem xs="12" Class="justify-center"> <MudStack> <MudStack Row> <MudCheckBox Label="Dense" @bind-Value="_dense" /> <MudCheckBox Label="Square" @bind-Value="_square" /> </MudStack> <MudRadioGroup @bind-Value="_variant"> <MudRadio Value="@Variant.Text" Label="Text" /> <MudRadio Value="@Variant.Outlined" Label="Outlined" /> <MudRadio Value="@Variant.Filled" Label="Filled" /> </MudRadioGroup> <MudStack Row Class="ml-4" Style="max-width:600px;"> <MudSelect Class="mr-1" T="MudBlazor.Color" Label="Chat Color" @bind-Value="_selectedColor"> @foreach (MudBlazor.Color color in Enum.GetValues(typeof(MudBlazor.Color))) { <MudSelectItem Value="">@color.ToString()</MudSelectItem> } </MudSelect> <MudSelect T="MudBlazor.ChatArrowPosition" Label="Chat Arrow" @bind-Value="_selectedArrowPosition"> @foreach (MudBlazor.ChatArrowPosition pos in Enum.GetValues(typeof(MudBlazor.ChatArrowPosition))) { <MudSelectItem Value="">@pos.ToString()</MudSelectItem> } </MudSelect> </MudStack> <MudSlider @bind-Value="_elevation" Min="0" Max="25" Color="Color.Info" Class="ml-4 mb-6" Style="max-width:600px;">Elevation: @_elevation.ToString()</MudSlider> </MudStack> </MudItem> </MudGrid> <MudChat Color="_selectedColor" Dense="@_dense" Elevation="@_elevation" Variant="@_variant" Square="_square" ArrowPosition="_selectedArrowPosition" ChatPosition="ChatBubblePosition.Start"> <MudChatHeader Name="Anakin" Time="12:46" /> <MudAvatar Size="@(_dense ? Size.Small : Size.Medium)"> <MudImage Src="images/toiletvisit.jpg" /> </MudAvatar> <MudChatBubble>What kind of nonsense is this</MudChatBubble> <MudChatBubble>Put me on the Council and not make me a Master!??</MudChatBubble> <MudChatBubble>That's never been done in the history of the Jedi. It's insulting!</MudChatBubble> <MudChatFooter Text="Seen at 12:46" /> </MudChat> <MudChat Color="_selectedColor" Dense="@_dense" Elevation="@_elevation" Variant="@_variant" Square="_square" ArrowPosition="_selectedArrowPosition" ChatPosition="ChatBubblePosition.End"> <MudChatHeader Name="Obi-Wan Kenobi" Time="12:45" /> <MudAvatar Size="@(_dense ? Size.Small : Size.Medium)"> <MudImage Src="images/jonny.jpg" /> </MudAvatar> <MudChatBubble>Calm down, Anakin. You have been given a great honor. <br/> To be on the Council at your age.</MudChatBubble> <MudChatBubble Color="Color.Primary">It's never happened before.</MudChatBubble> <MudChatFooter Text="Delivered" /> </MudChat>
@code { private bool _dense = true; private bool _square = false; private int _elevation = 5; private Variant _variant = Variant.Text; private Color _selectedColor = Color.Default; private ChatArrowPosition _selectedArrowPosition = ChatArrowPosition.Top; }
Adding a Hover Event
MudChat
and MudChatBubble
can be customized with any html classes, styles, and normal events.
Here is an example of adding a hovering like/reply center.
@inject ISnackbar Snackbar @inject IScrollListenerFactory ScrollListenerFactory @{ var orderedGroups = messages .OrderByDescending(m => m.Time) .GroupBy(m => m.Name) .ToList(); for (int i = 0; i < orderedGroups.Count; i++) { var group = orderedGroups[i]; var position = i == 0 ? ChatBubblePosition.Start : ChatBubblePosition.End; <MudChat ChatPosition=""> <MudAvatar>@group.First().Initials</MudAvatar> <MudChatHeader Name="@group.Key" Time="@group.First().Time" /> @foreach (var message in group.OrderByDescending(m => m.Time)) { <MudChatBubble OnClick="@((args) => ClickMessage(args, message))" OnContextClick="@((args) => RightClickMessage(args, message))" @onmouseenter="@((args) => HoverStart(args, message))" @onmouseleave="@(() => HoverStop("bubble"))"> @message.Text <MudPopover Open="@(Hovering && message.Equals(_hoverMessage))" Class="hoverarea" AnchorOrigin="Origin.CenterRight" TransformOrigin="Origin.BottomRight" @onscroll="@(() => HoverStop("scroll"))" @onmouseenter="@(() => _paperHovering = true)" @onmouseleave="@(() => HoverStop("paper"))"> <div class="d-flex" style="width: 100%;" @onclick:stopPropagation="true" @onclick:preventDefault="true"> <span class="emoji" @onclick="@(() => MessageAction("liked"))">👍</span> <span class="emoji" @onclick="@(() => MessageAction("cried"))">😭</span> <span class="emoji" @onclick="@(() => MessageAction("angered"))">👿</span> <MudDivider Class="mx-1" Vertical="true" FlexItem="true" /> <MudTooltip Text="Reply"> <span class="emoji" @onclick="">↩️</span> </MudTooltip> </div> </MudPopover> </MudChatBubble> <MudChatFooter> <MudPaper Class="actionarea" Elevation="0"> <div class="d-flex" style="width: 100%;" @onclick:stopPropagation="true" @onclick:preventDefault="true"> @if (message.Likes > 0) { <span class="emoji" @onclick="@(() => MessageAction("liked"))">👍</span> @message.Likes } @if (message.Cries > 0) { <span class="emoji" @onclick="@(() => MessageAction("cried"))">😭</span> @message.Cries } @if (message.Angers > 0) { <span class="emoji" @onclick="@(() => MessageAction("angered"))">👿</span> @message.Angers } </div> </MudPaper> </MudChatFooter> } </MudChat> } } <MudMenu PositionAtCursor="true" @ref="_contextMenu" id="_contextMenu"> <MudMenuItem Icon="@Icons.Material.Filled.Block" OnClick=""> Ban @_selectedMessage?.Name </MudMenuItem> <MudMenuItem Icon="@Icons.Material.Filled.Info" OnClick=""> View Details for @_selectedMessage?.Name </MudMenuItem> </MudMenu> <style> .hoverarea { cursor: pointer !important; background-color: var(--mud-palette-appbar-background); color: var(--mud-palette-appbar-text); transition: opacity 0.3s ease; opacity: .8; } .actionarea { background-color: var(--mud-palette-appbar-background); color: var(--mud-palette-appbar-text); } .actionarea:focus { opacity: 1; } span.emoji { font-size: 12px; padding: 1px 1px; align-self: center; } </style>
@code { #nullable enable private IScrollListener? _scrollListener; private List<Message> messages = new(); private Message? _selectedMessage; private MudMenu? _contextMenu; private bool Hovering => _paperHovering || _bubbleHovering; private bool _bubbleHovering; private bool _paperHovering; private Message? _hoverMessage; protected override void OnInitialized() { _scrollListener = ScrollListenerFactory.Create(null); _scrollListener.OnScroll += OnScrollAsync; messages.Add(new Message("Obi-Wan Kenobi", "OK", "You were my brother Anakin.", "2 hours ago")); messages.Add(new Message("Obi-Wan Kenobi", "OK", "I loved you.", "2 hours ago")); messages.Add(new Message("Anakin Skywalker", "AS", "I'm sorry.", "1 hour ago")); } private void OnScrollAsync(object? sender, ScrollEventArgs e) { HoverStop("scroll"); } public void Dispose() { if (_scrollListener != null) _scrollListener.OnScroll -= OnScrollAsync; } private void HoverStart(MouseEventArgs args, Message message) { _bubbleHovering = true; _hoverMessage = message; } private void HoverStop(string typeOfStop) { try { switch (typeOfStop) { case "paper": _paperHovering = false; break; case "bubble": _bubbleHovering = false; break; case "scroll": _paperHovering = false; _bubbleHovering = false; StateHasChanged(); break; default: break; } } catch { } } private void MessageAction(string actionType) { switch (actionType) { case "liked": _hoverMessage!.Likes++; break; case "cried": _hoverMessage!.Cries++; break; case "angered": _hoverMessage!.Angers++; break; default: break; } } private void Reply() { if (_hoverMessage is null) { Snackbar.Add("No message available!", Severity.Warning); } else { Snackbar.Add($"Simulate Reply: To: {_hoverMessage.Name}", Severity.Success); } } private void ShowHiddenInfo() { if (_selectedMessage is not null) { Snackbar.Add($"Hidden information for {_selectedMessage.Name}", Severity.Info); } } private void BanUser() { if (_selectedMessage is not null) { Snackbar.Add($"{_selectedMessage.Name} has been banned!", Severity.Error); } } private async Task RightClickMessage(MouseEventArgs args, Message message) { _selectedMessage = message; if (_contextMenu != null) await _contextMenu.OpenMenuAsync(args); } private async Task ClickMessage(MouseEventArgs args, Message message) { _selectedMessage = message; Snackbar.Add("Message clicked: " + message.Text, Severity.Info); await Task.CompletedTask; } private record Message( string Name, string Initials, string Text, string Time, int Likes = 0, int Cries = 0, int Angers = 0) { public int Likes { get; set; } = Likes; public int Cries { get; set; } = Cries; public int Angers { get; set; } = Angers; } }