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

ChatView | Input Bar & Tools

The input bar sits at the bottom of the ChatView and provides the primary message composition interface:

┌─────────────────────────────────────────┐
│ […] [+] Type a message... [Send] │
└─────────────────────────────────────────┘
↑ ↑ ↑
Tools Attach Send
button button button
  • Tools button (left) — Opens a floating menu for camera, voice, etc. (MAUI only, shown when ToolItems has items)
  • Attach button — Shows when AttachImageCommand is bound
  • Text entry — Placeholder text, Enter-to-send
  • Send button — Fires SendCommand with trimmed text
<shiny:ChatView Messages="{Binding Messages}"
SendCommand="{Binding SendCommand}"
PlaceholderText="Ask me anything..."
SendButtonText="Send"
SendButtonBackgroundColor="#007AFF"
SendButtonTextColor="White"
InputBarBackgroundColor="#F5F5F5"
InputBarBorderColor="#E0E0E0"
IsInputBarVisible="True" />
PropertyTypeDefaultDescription
PlaceholderTextstring"Type a message..."Input field placeholder
SendButtonTextstring"Send"Send button label
SendButtonBackgroundColorColor#007AFFSend button background color (MAUI only)
SendButtonTextColorColorWhiteSend button text color (MAUI only)
InputBarBackgroundColorColor#F5F5F5Input bar background color (MAUI only)
InputBarBorderColorColor#E0E0E0Input bar top separator/border color (MAUI only)
IsInputBarVisiblebooltrueShow/hide the entire input bar
EntryTextstring""Get/set current input text (MAUI only)

Messages are sent when:

  1. The user taps the Send button
  2. The user presses Enter/Return (MAUI) or Enter without Shift (Blazor)

The SendCommand receives the trimmed text string. Empty/whitespace-only text is ignored. The input field is automatically cleared after a successful send.

On Blazor, Shift+Enter allows multiline input without triggering send. On MAUI, the entry is single-line by default.

// Set text without sending
chatView.EntryText = "Pre-filled response";
// Programmatically trigger send
chatView.SubmitEntry();

This is how tools like SpeechToTextTool inject transcribed text and optionally auto-send it.

The attach button (”+”) appears automatically when AttachImageCommand is bound:

<shiny:ChatView SendCommand="{Binding SendCommand}"
AttachImageCommand="{Binding AttachCommand}" />
[RelayCommand]
async Task Attach()
{
var result = await MediaPicker.PickPhotoAsync();
if (result is not null)
{
Messages.Add(new ChatMessage
{
ImageUrl = result.FullPath,
SenderId = "me",
IsFromMe = true,
Timestamp = DateTimeOffset.Now
});
}
}

When AttachImageCommand is null or not bound, the button is hidden.

Add a floating action button menu to the left of the input bar for multiple composition actions:

<shiny:ChatView Messages="{Binding Messages}"
SendCommand="{Binding SendCommand}"
ToolsIcon="tools.png"
ToolsFabBackgroundColor="#007AFF">
<shiny:ChatView.ToolItems>
<shiny:ChatEntryTool Text="Camera"
Icon="camera.png"
FabBackgroundColor="#4CAF50"
Command="{Binding TakePhotoCommand}" />
<shiny:ChatEntryTool Text="Gallery"
Icon="gallery.png"
FabBackgroundColor="#FF9800"
Command="{Binding PickImageCommand}" />
<shiny:ChatEntryTool Text="Location"
Icon="location.png"
FabBackgroundColor="#2196F3"
Command="{Binding ShareLocationCommand}" />
</shiny:ChatView.ToolItems>
</shiny:ChatView>
PropertyTypeDefaultDescription
ToolItemsIList<ChatEntryTool>nullItems shown in the tools FAB menu
ToolsIconImageSourcenullIcon on the main tools button
ToolsTextstring?nullText label for the tools button
ToolsFabBackgroundColorColor#007AFFBackground color of the tools button

When ToolItems is empty or null, the tools button is hidden.

The tools menu expands upward with a staggered animation:

  • 30ms stagger between each item appearing
  • 200ms duration per item (fade + translate from below)
  • Semi-transparent backdrop covers the chat area
  • Tapping the backdrop or any item closes the menu

A pre-built tool that records speech and inserts the transcription into the input field. Requires the Shiny.Maui.Controls.SpeechAddins package.

<shiny:ChatView.ToolItems>
<shiny:SpeechToTextTool AutoSend="False"
SilenceTimeout="00:00:03"
Culture="en-US" />
</shiny:ChatView.ToolItems>
PropertyTypeDefaultDescription
AutoSendboolfalseAutomatically submit text after speech completes
SilenceTimeoutTimeSpan2 secondsHow long to wait for silence before stopping
Culturestring?nullBCP 47 language code (null = device default)
PreferOnDeviceboolfalsePrefer on-device recognition over cloud
ListeningIconImageSource?nullIcon shown while recording
ListeningTextstring"Listening…"Label shown while recording
ListeningFabBackgroundColorColor#F44336 (red)Button color while recording

Behavior:

  1. First tap starts listening — icon/text/color change to indicate recording state
  2. Speech is transcribed in real-time and appended to chatView.EntryText
  3. Recording stops on: second tap, silence timeout, or error
  4. If AutoSend = true, chatView.SubmitEntry() is called after recording stops

Requirements:

  • Package: Shiny.Maui.Controls.SpeechAddins
  • DI: ISpeechToTextService from Shiny.Speech must be registered
  • Namespace: Shiny.Maui.Controls.SpeechAddins.Chat

A pre-built tool that opens the device photo gallery using MAUI MediaPicker and fires AttachImageCommand with the selected file path.

<shiny:ChatView.ToolItems>
<shiny:PhotoGalleryEntryTool PickerTitle="Select a photo" />
</shiny:ChatView.ToolItems>
PropertyTypeDefaultDescription
PickerTitlestring"Select a photo"Title displayed on the media picker dialog

Behavior:

  1. Tap opens the device photo gallery via MediaPicker.Default.PickPhotoAsync()
  2. If the user selects a photo, ChatView.AttachImageCommand is executed with FileResult.FullPath
  3. If cancelled or permission denied, no action is taken

Requirements:

  • Package: Shiny.Maui.Controls
  • The ChatView.AttachImageCommand must be bound to handle the file path string

A pre-built tool that opens the device camera using MAUI MediaPicker and fires AttachImageCommand with the captured photo path.

<shiny:ChatView.ToolItems>
<shiny:TakePhotoEntryTool PickerTitle="Take a photo" />
</shiny:ChatView.ToolItems>
PropertyTypeDefaultDescription
PickerTitlestring"Take a photo"Title displayed on the media picker dialog

Behavior:

  1. Checks MediaPicker.Default.IsCaptureSupported — if not supported, does nothing
  2. Tap opens the device camera via MediaPicker.Default.CapturePhotoAsync()
  3. If the user captures a photo, ChatView.AttachImageCommand is executed with FileResult.FullPath
  4. If cancelled or permission denied, no action is taken

Requirements:

  • Package: Shiny.Maui.Controls
  • The ChatView.AttachImageCommand must be bound to handle the file path string
  • Device must support camera capture

Tools that need access to the ChatView’s input system should inherit from ChatEntryTool. It can also be used directly in XAML with a Command binding for simple tools:

public class ChatEntryTool : FabMenuItem
{
protected ChatView? ChatView { get; private set; }
// Attach/Detach called automatically by ChatView
}

When ToolItems is set on a ChatView, each tool’s Attach() method is called automatically, giving it a reference to the parent ChatView.

This gives your tool access to:

  • ChatView.EntryText — Read/write the input field
  • ChatView.SubmitEntry() — Programmatically send
  • The full ChatView state (messages, participants, etc.)
public class QuickReplyTool : ChatEntryTool
{
public QuickReplyTool()
{
Text = "Quick Reply";
FabBackgroundColor = Colors.Purple;
Clicked += OnClicked;
}
void OnClicked(object? sender, EventArgs e)
{
if (ChatView is null) return;
ChatView.EntryText = "Thanks, I'll get back to you shortly!";
ChatView.SubmitEntry();
}
}
<shiny:ChatView.ToolItems>
<local:QuickReplyTool />
</shiny:ChatView.ToolItems>
public class TemplateTool : ChatEntryTool
{
readonly string[] templates = {
"I'll look into this and get back to you.",
"Thanks for reaching out!",
"Let me connect you with the right team."
};
public TemplateTool()
{
Text = "Templates";
FabBackgroundColor = Colors.Teal;
Clicked += OnClicked;
}
async void OnClicked(object? sender, EventArgs e)
{
if (ChatView is null) return;
var result = await Application.Current!.MainPage!
.DisplayActionSheet("Pick a template", "Cancel", null, templates);
if (result != null && result != "Cancel")
{
ChatView.EntryText = result;
// Don't auto-send — let user review/edit first
}
}
}

Set IsInputBarVisible = false for read-only or externally-controlled scenarios:

<shiny:ChatView Messages="{Binding Messages}"
IsInputBarVisible="False" />

Use cases:

  • Read-only chat history
  • Chat controlled by external UI (buttons, cards)
  • Bot conversations with only button-based interaction
  • Review/audit views of past conversations