A rich, ready-to-use UI controls library for both .NET MAUI and Blazor. One package per host covers TableView, Scheduler, FloatingPanel/OverlayHost, ShinyDurationPicker, FrostedGlassView, Toast, Fab/FabMenu, PillView, SecurityPin, SignaturePad, ImageViewer, ImageEditor, ChatView, ColorPicker, FontPicker, Slider, ProgressBar, Overlay/LoadingOverlay, AutoCompleteEntry, CountryPicker, AddressEntry, TextEntry, CarouselGallery, StaggeredGrid, and VirtualizedGrid. Markdown and Mermaid Diagrams ship as separate add-on packages per host.
dotnet add package Shiny.Maui.ControlsRegister in your MauiProgram.cs:
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseShinyControls();Add the XAML namespace:
xmlns:shiny="http://shiny.net/maui/controls"For Markdown controls (separate package):
dotnet add package Shiny.Maui.Controls.Markdownxmlns:md="http://shiny.net/maui/markdown"For Mermaid Diagrams (separate package):
dotnet add package Shiny.Maui.Controls.MermaidDiagramsxmlns:diagram="http://shiny.net/maui/diagrams"dotnet add package Shiny.Blazor.Controls
dotnet add package Shiny.Blazor.Controls.Markdown # optional
dotnet add package Shiny.Blazor.Controls.MermaidDiagrams # optionalAdd the @using directives — typically in _Imports.razor:
@using Shiny.Blazor.Controls
@using Shiny.Blazor.Controls.Cells
@using Shiny.Blazor.Controls.Sections
@using Shiny.Blazor.Controls.Scheduler
@using Shiny.Blazor.Controls.Markdown
@using Shiny.Blazor.Controls.MermaidDiagramsNo DI registration is required — drop the components into any .razor page.
| MAUI (XAML) | Blazor (Razor) |
|---|---|
<shiny:TableView> with <shiny:TableRoot> |
<TableView> (no TableRoot wrapper) |
<shiny:PillView> |
<Pill> |
<shiny:FloatingPanel> in <shiny:OverlayHost> |
<SheetView> with <SheetContent> child (Blazor uses CSS overlay) |
Value="{Binding Pin}" (TwoWay) |
@bind-Value="pin" |
IsOpen="{Binding IsOpen, Mode=TwoWay}" |
@bind-IsOpen="isOpen" |
Command="{Binding DoCommand}" |
OnClick="DoAsync" / Clicked="DoAsync" |
Color type (e.g. Colors.Blue) |
CSS color string (e.g. "#2196F3") |
Fab.Icon="add.png" (ImageSource) |
<Fab Icon="+"> (inline text/SVG string) |
shiny:CarouselGallery |
<CarouselGallery> — PeekAreaInsets → PeekAmount; adds ShowIndicators |
shiny:StaggeredGrid |
<StaggeredGrid> — ItemSelectedCommand → ItemSelected EventCallback |
shiny:VirtualizedGrid |
<VirtualizedGrid> — CellPadding → individual padding props; adds EnableVirtualization, GroupedItems |
ItemTemplate as DataTemplate |
ItemTemplate as RenderFragment<object> |
IToaster.ShowAsync(text, cfg => {}) (DI) |
IToastService.ShowAsync(text, cfg => {}) (DI + <ToastHost />) |
<shiny:TextEntry> |
<TextEntry> |
<shiny:Overlay> in <shiny:ShinyContentPage.Panels> |
<Overlay> (wraps ChildContent; custom content in <OverlayContent> slot) |
<shiny:LoadingOverlay> in <shiny:ShinyContentPage.Panels> |
<LoadingOverlay> (wraps ChildContent) |
<shiny:ProgressBar> |
<ProgressBar> |
ISchedulerEventProvider is identical across both hosts.
Calendar and agenda views for displaying events and appointments, powered by ISchedulerEventProvider.
| Calendar | Agenda | Event List |
|---|---|---|
![]() |
![]() |
![]() |
SchedulerCalendarView - Month calendar grid with event indicators, swipe navigation, and date selection.
<shiny:SchedulerCalendarView
Provider="{Binding Provider}"
SelectedDate="{Binding SelectedDate}"
DisplayMonth="{Binding DisplayMonth}" />SchedulerAgendaView - Day/multi-day timeline with time slots, overlapping event layout, current time marker, optional timezone columns, and switchable date picker modes (carousel, calendar sheet, or none).
<shiny:SchedulerAgendaView
Provider="{Binding Provider}"
SelectedDate="{Binding SelectedDate}"
DaysToShow="{Binding DaysToShow}"
DatePickerMode="Calendar"
ShowAdditionalTimezones="{Binding ShowAdditionalTimezones}" />DatePickerMode options: Carousel (default horizontal day picker), Calendar (collapsible month calendar with pull-to-expand), None (no picker).
SchedulerCalendarListView - Scrollable event list grouped by day with infinite scroll loading.
<shiny:SchedulerCalendarListView
Provider="{Binding Provider}"
SelectedDate="{Binding SelectedDate}" />ISchedulerEventProvider - Implement this interface to supply event data:
public class MyEventProvider : ISchedulerEventProvider
{
public Task<IReadOnlyList<SchedulerEvent>> GetEvents(DateTimeOffset start, DateTimeOffset end) { ... }
public void OnEventSelected(SchedulerEvent selectedEvent) { ... }
public bool CanCalendarSelect(DateOnly selectedDate) => true;
public void OnCalendarDateSelected(DateOnly selectedDate) { }
public bool CanSelectAgendaTime(DateTimeOffset selectedTime) => true;
public void OnAgendaTimeSelected(DateTimeOffset selectedTime) { }
}A floating panel overlay system for MAUI. Panels slide in from the bottom or top of the screen with configurable snap positions (detents), optional header peek when closed, backdrop dimming, and feedback. Multiple panels can coexist on the same page without blocking touches on content underneath.
OverlayHost is a transparent Grid layer that manages backdrop and touch passthrough for overlay clients (FloatingPanel, Overlay, LoadingOverlay). ShinyContentPage is a convenience ContentPage with a built-in OverlayHost.
| Closed | Open | Header (Closed) | Header (Open) | Top (Closed) | Top (Open) |
|---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
<!-- Using ShinyContentPage (recommended) -->
<shiny:ShinyContentPage xmlns:shiny="http://shiny.net/maui/controls">
<shiny:ShinyContentPage.PageContent>
<!-- Your page content here -->
</shiny:ShinyContentPage.PageContent>
<shiny:ShinyContentPage.Panels>
<shiny:FloatingPanel
IsOpen="{Binding IsSheetOpen}"
Position="Bottom"
HasBackdrop="True"
CloseOnBackdropTap="True"
PanelCornerRadius="16">
<shiny:FloatingPanel.Detents>
<shiny:DetentValue Value="Quarter" />
<shiny:DetentValue Value="Half" />
<shiny:DetentValue Value="Full" />
</shiny:FloatingPanel.Detents>
<!-- Your panel content here -->
</shiny:FloatingPanel>
</shiny:ShinyContentPage.Panels>
</shiny:ShinyContentPage>FloatingPanel Properties:
| Property | Type | Description |
|---|---|---|
| IsOpen | bool | Show/hide the panel (TwoWay) |
| Position | FloatingPanelPosition | Bottom, BottomTabs, or Top — which edge the panel slides from. Use BottomTabs when inside a Shell TabBar to clip above the tab bar |
| Detents | ObservableCollection<DetentValue> | Snap positions (Quarter, Half, Full) |
| PanelContent | View | Content displayed in the panel ([ContentProperty]) |
| HeaderTemplate | View | Optional header view at the screen edge; shown as a peek bar when closed |
| ShowHeaderWhenClosed | bool | When true, the header peeks from the edge when the panel is closed |
| HasBackdrop | bool | Fade backdrop behind panel |
| CloseOnBackdropTap | bool | Close when backdrop tapped |
| PanelCornerRadius | double | Corner radius |
| HandleColor | Color | Drag handle color |
| ShowHandle | bool | Show/hide the drag handle bar |
| PanelBackgroundColor | Color | Panel background color |
| AnimationDuration | double | Animation speed (ms) |
| ExpandOnInputFocus | bool | Auto-expand when input focused |
| IsLocked | bool | Prevents drag dismiss; code-only control |
| FitContent | bool | Auto-computes detent from content size |
| UseFeedback | bool | Feedback on open, close, and detent snap (default: true) |
OverlayHost Properties:
| Property | Type | Description |
|---|---|---|
| BackdropColor | Color | Backdrop color (default: Black) |
| BackdropMaxOpacity | double | Maximum backdrop opacity (default: 0.5) |
ShinyContentPage Properties:
| Property | Type | Description |
|---|---|---|
| PageContent | View | Main page content |
| Panels | IList<IView> | Collection of FloatingPanel, Overlay, and LoadingOverlay instances |
| BackdropColor | Color | Forwarded to internal OverlayHost |
| BackdropMaxOpacity | double | Forwarded to internal OverlayHost |
A standalone duration picker control that opens a FloatingPanel for selection with hour/minute pickers and "hr"/"min" labels. Requires ShinyContentPage (or an OverlayHost in the visual tree).
<shiny:ShinyDurationPicker Duration="{Binding SelectedDuration, Mode=TwoWay}"
MinDuration="0:15:00"
MaxDuration="8:00:00"
MinuteInterval="5"
Placeholder="Choose duration" />| Property | Type | Default | Description |
|---|---|---|---|
Duration |
TimeSpan? |
null |
Selected duration (TwoWay) |
MinDuration |
TimeSpan |
0:00:00 |
Minimum duration |
MaxDuration |
TimeSpan |
24:00:00 |
Maximum duration |
MinuteInterval |
int |
5 |
Minute increment step |
Format |
string |
@"h\:mm" |
Display format string |
Placeholder |
string |
"Select duration" |
Text shown when no duration selected |
A full-screen image overlay with pinch-to-zoom, pan, double-tap zoom, and animated open/close transitions.
| Gallery | Viewer |
|---|---|
![]() |
![]() |
<Grid>
<!-- Page content with tappable images -->
<ScrollView>
<VerticalStackLayout>
<Image Source="photo.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OpenViewerCommand}"
CommandParameter="photo.png" />
</Image.GestureRecognizers>
</Image>
</VerticalStackLayout>
</ScrollView>
<!-- ImageViewer overlays on top -->
<shiny:ImageViewer Source="{Binding SelectedImage}"
IsOpen="{Binding IsViewerOpen}" />
</Grid>| Property | Type | Description |
|---|---|---|
| Source | ImageSource? | The image to display |
| IsOpen | bool | Show/hide the viewer (TwoWay) |
| Aspect | Aspect | Image aspect ratio mode (default: AspectFit) |
| MaxZoom | double | Maximum zoom scale (default: 5.0) |
| CloseButtonTemplate | DataTemplate? | Custom close button (tapping closes viewer) |
| HeaderTemplate | DataTemplate? | Custom header overlay |
| FooterTemplate | DataTemplate? | Custom footer overlay |
| UseFeedback | bool | Enable/disable feedback on double-tap zoom (default: true) |
Features:
- Pinch-to-zoom with origin tracking
- Pan when zoomed (clamped to image bounds)
- Double-tap to zoom in (2.5x) / reset
- Animated fade open/close with backdrop
- Close button overlay
An inline image editor with cropping, rotation, freehand drawing, line and arrow drawing, text annotations with font family and font size selection, and zoom. Includes a built-in undo/redo stack, reset-to-original, and export to PNG/JPEG/WEBP at configurable resolutions. Every feature can be toggled on/off, and the default toolbar can be replaced with a custom template.
| Editor | Crop Mode |
|---|---|
![]() |
![]() |
<shiny:ImageEditor Source="{Binding ImageSource}"
CurrentToolMode="{Binding ToolMode}"
AllowCrop="True"
AllowRotate="True"
AllowDraw="True"
AllowTextAnnotation="True"
DrawStrokeColor="Red"
DrawStrokeWidth="3" />| Property | Type | Default | Description |
|---|---|---|---|
| Source | ImageSource? | null | Image to edit (supports file, stream, URI) |
| CurrentToolMode | ImageEditorToolMode | Move | Active tool (Move, Crop, Draw, Text, Line, Arrow) — TwoWay |
| AllowCrop | bool | true | Enable/disable crop tool |
| AllowRotate | bool | true | Enable/disable rotate action |
| AllowDraw | bool | true | Enable/disable freehand drawing |
| AllowTextAnnotation | bool | true | Enable/disable text annotation |
| AllowLine | bool | true | Enable/disable line drawing tool |
| AllowFontSelection | bool | false | Show font picker button in text mode |
| AllowFontSizeSelection | bool | false | Show font size picker button in text mode |
| AllowZoom | bool | true | Enable/disable pinch-to-zoom |
| CanUndo | bool | false | Whether undo is available (OneWayToSource) |
| CanRedo | bool | false | Whether redo is available (OneWayToSource) |
| DrawStrokeColor | Color | White | Drawing stroke color — TwoWay |
| DrawStrokeWidth | double | 3 | Drawing stroke width |
| TextFontSize | double | 16 | Text annotation font size |
| TextFontFamily | string? | null | Font family for text annotations (TwoWay) |
| AnnotationTextColor | Color | White | Text annotation color |
| AvailableFonts | IList<string>? | null | Font families shown in font picker |
| AvailableFontSizes | IList<double>? | null | Font sizes shown in font size picker |
| SaveCommand | ICommand? | null | Invoked with EditedImage parameter on save |
| SaveText | string | "Save" | Save button label |
| CropApplyText | string | "Apply Crop" | Crop apply button label |
| CropCancelText | string | "Cancel" | Crop cancel button label |
| ToolbarTemplate | DataTemplate? | null | Custom toolbar (replaces default) |
| ToolbarPosition | ToolbarPosition | Bottom | Toolbar placement (Top or Bottom) |
| UseFeedback | bool | true | Feedback on actions |
Features:
- Move mode with pinch-to-zoom and pan (origin-aware, double-tap to toggle)
- Crop with drag handles, rule-of-thirds grid, dimmed overlay, and dedicated Apply/Cancel toolbar
- 90° rotation (or arbitrary angles)
- Freehand drawing with configurable color and stroke width (constrained to image bounds)
- Line and arrow drawing between two points with configurable color and width
- Inline text annotations placed by tapping the image with optional font family and size selection
- Integrated color picker for draw color
- Font picker and font size picker integration (when
AllowFontSelection/AllowFontSizeSelectionenabled) - Undo/redo for every edit action
- Reset to original image
- Save via
SaveCommandwithEditedImage— callToStreamAsync(format)to get PNG, JPEG, or WEBP - Image border showing the drawable surface area
Commands: UndoCommand, RedoCommand, RotateCommand, ResetCommand, CropCommand, DrawCommand, TextCommand, LineCommand, SaveCommand
Methods: Undo(), Redo(), Rotate(float), Reset(), ApplyCrop(), GetEditedImage()
A modern chat UI control with message bubbles, typing indicators, load-more pagination, acknowledgement reactions, bubble tools, custom message templates, and a configurable input bar. Supports single-person and multi-person conversations with per-participant colors and avatars.
<shiny:ChatView Messages="{Binding Messages}"
Participants="{Binding Participants}"
IsMultiPerson="True"
TypingParticipants="{Binding TypingParticipants}"
SendCommand="{Binding SendCommand}"
AttachImageCommand="{Binding AttachImageCommand}"
LoadMoreCommand="{Binding LoadMoreCommand}"
MyBubbleColor="#DCF8C6"
OtherBubbleColor="White"
PlaceholderText="Type a message..." />| Property | Type | Default | Description |
|---|---|---|---|
| Messages | IList<ChatMessage> | null | Bindable message collection (supports INotifyCollectionChanged) |
| Participants | IList<ChatParticipant> | null | Participant info for avatar/color lookup |
| IsMultiPerson | bool | false | Show avatars and names for other participants |
| ShowAvatarsInSingleChat | bool | false | Force avatars even in single-person mode |
| MyBubbleColor | Color | #DCF8C6 | Local user bubble color |
| MyTextColor | Color | Black | Local user text color |
| OtherBubbleColor | Color | White | Default other-user bubble color |
| OtherTextColor | Color | Black | Other-user text color |
| ChatBackgroundColor | Color? | null | Background color for the messages area |
| BubbleFontSize | double | 15 | Font size for bubble text |
| BubbleFontFamily | string? | null | Font family for bubble text |
| TimestampFontSize | double | 11 | Font size for timestamps |
| BubbleCornerRadius | double | 18 | Corner radius for bubbles (tail stays at 4) |
| PlaceholderText | string | "Type a message..." | Input placeholder |
| SendButtonText | string | "Send" | Send button label |
| SendButtonBackgroundColor | Color | #007AFF | Send button background color |
| SendButtonTextColor | Color | White | Send button text color |
| InputBarBackgroundColor | Color | #F5F5F5 | Input bar background color |
| InputBarBorderColor | Color | #E0E0E0 | Input bar top border color |
| IsInputBarVisible | bool | true | Show/hide the input bar |
| ShowTypingIndicator | bool | true | Enable typing notifications |
| TypingParticipants | IList<ChatParticipant> | null | Currently typing participants |
| ScrollToFirstUnread | bool | false | Scroll to first unread instead of end |
| FirstUnreadMessageId | string? | null | ID of the first unread message |
| ToolItems | IList<ChatEntryTool> | null | Input bar tools FAB menu (MAUI only) |
| BubbleToolItems | IList<ChatBubbleTool> | null | Bubble tools for received (other user) messages (MAUI only) |
| MyBubbleToolItems | IList<ChatBubbleTool> | null | Bubble tools for the local user's own messages (MAUI only) |
| MessageTemplate | DataTemplate? | null | Single template for all message content (MAUI only) |
| MessageTemplateSelector | DataTemplateSelector? | null | Per-type template selector (MAUI only) |
| UseFeedback | bool | true | Haptic feedback on interactions (MAUI only) |
Commands: SendCommand (text string), AttachImageCommand, LoadMoreCommand, MessageTappedCommand (ChatMessage)
Methods (MAUI): ScrollToEnd(bool animate), ScrollToMessage(string messageId, bool animate), SubmitEntry(), EntryText (get/set)
Tool Base Classes (MAUI only):
| Class | Purpose |
|---|---|
ChatEntryTool |
Base for input bar tools needing ChatView access (ChatView property auto-populated). Non-abstract — use directly with Command binding or subclass for self-contained tools. |
ChatBubbleTool |
Base for bubble tools acting on a message (Message property auto-populated). Non-abstract — use directly with Command binding or subclass. |
CopyBubbleTool |
Built-in: copies message text to clipboard |
TextToSpeechBubbleTool |
Built-in: reads message aloud (requires Shiny.Maui.Controls.SpeechAddins) |
SpeechToTextTool |
Built-in: voice input for chat entry (requires Shiny.Maui.Controls.SpeechAddins) |
PhotoGalleryEntryTool |
Built-in: opens device photo gallery via MediaPicker, fires AttachImageCommand with file path |
TakePhotoEntryTool |
Built-in: opens device camera via MediaPicker, fires AttachImageCommand with file path |
AcknowledgementBubbleTool |
Built-in: single-tap toggle for a specific reaction emoji (e.g. 👍, 👎). Set Glyph property. |
AcknowledgementSelectorBubbleTool |
Built-in: opens action sheet with 12 common emoji reactions to choose from |
// Use ChatEntryTool directly with a Command binding
// <shiny:ChatEntryTool Text="Camera" Command="{Binding TakePhotoCommand}" />
// Or subclass for self-contained tools
public class QuickReplyTool : ChatEntryTool
{
public QuickReplyTool() { Text = "Quick Reply"; Clicked += (s, e) => { ChatView?.EntryText = "Thanks!"; ChatView?.SubmitEntry(); }; }
}
// Use ChatBubbleTool directly — Command receives AcknowledgementChangedContext or ChatMessage via CommandParameter
// <shiny:ChatBubbleTool Text="Translate" Command="{Binding TranslateCommand}" />
// Or subclass for self-contained tools
public class TranslateTool : ChatBubbleTool
{
public TranslateTool() { Text = "Translate"; Clicked += async (s, e) => { if (Message != null) { /* translate Message.Text */ } }; }
}
// Built-in acknowledgement tools
// <shiny:AcknowledgementBubbleTool Glyph="👍" Command="{Binding AckCommand}" />
// <shiny:AcknowledgementSelectorBubbleTool Command="{Binding AckCommand}" />Features:
- Chat bubbles with left/right alignment and customizable colors per participant
- Visual grouping by sender and minute; timestamps on last message in each group
- Multi-person: avatar (initials or image) and name on first message in each group
- Typing indicators with animated dots, scroll-aware toast pill
- Acknowledgement reactions (emoji badges grouped by glyph with count)
- Bubble tools: per-message ⋮ menu with built-in and custom actions
- Input bar tools: FAB menu for camera, voice, custom actions
- Auto-link detection in text messages
- Image messages (text and image are mutually exclusive)
- DateSent pending state (null = pending/offline, renders at 50% opacity until server confirmation)
- Smart scrolling with unread message pill
- Load-more pagination (auto-trigger on MAUI, button on Blazor)
- Custom message templates for action buttons, cards, or rich content
- Entire input bar can be hidden for read-only use
A full-featured color picker with spectrum, hue bar, opacity slider, hex input, and preview swatch. Available as both an inline ColorPicker control and a ColorPickerButton that opens as a popup dialog.
| Button | Picker Dialog |
|---|---|
![]() |
![]() |
<shiny:ColorPickerButton SelectedColor="{Binding SelectedColor}"
Text="Pick Color"
ShowOpacity="True" />| Property | Type | Default | Description |
|---|---|---|---|
| SelectedColor | Color | Red | Currently selected color — TwoWay |
| Text | string? | null | Button label text |
| ShowOpacity | bool | false | Show/hide opacity slider |
| CornerRadius | int | 8 | Button corner radius |
| ColorChangedCommand | ICommand? | null | Fires when color changes |
Event: ColorChanged (EventHandler<Color>)
Font family and font size picker controls for MAUI. Includes inline list (FontPicker, FontSizePicker) and popup button (FontPickerButton, FontSizePickerButton) variants. Each font is rendered in its own typeface for instant visual preview.
<shiny:FontPickerButton AvailableFonts="{Binding Fonts}"
SelectedFont="{Binding SelectedFont, Mode=TwoWay}"
Placeholder="Font" />
<shiny:FontSizePickerButton AvailableFontSizes="{Binding Sizes}"
SelectedFontSize="{Binding SelectedSize, Mode=TwoWay}" />FontPicker / FontPickerButton:
| Property | Type | Default | Description |
|---|---|---|---|
| AvailableFonts | IList<string>? | null | Font family names to display |
| SelectedFont | string? | null | Currently selected font (TwoWay) |
| PreviewText | string | "The quick brown fox" | Text rendered in each font row |
| PreviewFontSize | double | 18 | Size of preview text |
| Placeholder | string | "Font" | Button placeholder (button only) |
| CornerRadius | int | 8 | Button corner radius (button only) |
| FontChangedCommand | ICommand? | null | Command on selection (button only) |
FontSizePicker / FontSizePickerButton:
| Property | Type | Default | Description |
|---|---|---|---|
| AvailableFontSizes | IList<double>? | null | Font sizes to display |
| SelectedFontSize | double | 16 | Currently selected size (TwoWay) |
| PreviewText | string | "Aa" | Text rendered at each size |
| CornerRadius | int | 8 | Button corner radius (button only) |
| FontSizeChangedCommand | ICommand? | null | Command on selection (button only) |
These controls are also integrated into the ImageEditor toolbar when AllowFontSelection and AllowFontSizeSelection are enabled.
A Material Design-inspired text entry control with animated floating placeholder, customizable border, left/right tool slots, hint text for validation errors, character count display, and input masking for formatted data entry.
<shiny:TextEntry Placeholder="Email"
Text="{Binding Email, Mode=TwoWay}"
Keyboard="Email"
HasError="{Binding HasEmailError}"
HintText="{Binding EmailError}">
<shiny:ClearButtonTool />
</shiny:TextEntry>| Property | Type | Default | Description |
|---|---|---|---|
| Text | string | "" | Current text value (TwoWay). When Mask is set, contains raw digits only |
| Placeholder | string | "" | Animated floating placeholder |
| PlaceholderColor | Color | Grey | Placeholder color unfocused |
| FocusedPlaceholderColor | Color | #007AFF | Placeholder color focused |
| BorderColor | Color | #CCCCCC | Border color unfocused |
| FocusedBorderColor | Color | #007AFF | Border color focused |
| BorderThickness | double | 1 | Unfocused border thickness |
| FocusedBorderThickness | double | 2 | Focused border thickness |
| CornerRadius | CornerRadius | 8 | Corner radius |
| EntryBackgroundColor | Color | Transparent | Background fill |
| IsReadOnly | bool | false | Read-only mode |
| IsPassword | bool | false | Password masking |
| Keyboard | Keyboard | Default | Keyboard type (auto-set to Numeric when Mask is active) |
| MaxLength | int | unlimited | Character limit |
| Mask | string? | null | Input mask pattern (# = digit slot, other chars are auto-inserted literals) |
| FormattedText | string | "" | Read-only display value with mask applied |
| HintText | string? | null | Hint/error text below field |
| HasError | bool | false | Error state |
| ErrorColor | Color | #DC3545 | Error color |
| ShowCharacterCount | bool | false | Show counter |
| LeftTools | IList<TextEntryTool> | empty | Left tool slot |
| RightTools | IList<TextEntryTool> | empty | Right tool slot (ContentProperty) |
Input Masking:
<shiny:TextEntry Placeholder="Phone Number" Mask="(###) ###-####" Text="{Binding Phone}" />
<shiny:TextEntry Placeholder="Credit Card" Mask="#### #### #### ####" Text="{Binding Card}" />
<shiny:TextEntry Placeholder="Date" Mask="##/##/####" Text="{Binding DateStr}" />When Mask is set, Text always contains raw digits (e.g., "5551234567"), while the user sees formatted text (e.g., "(555) 123-4567"). Keyboard auto-sets to Numeric and literal characters are inserted automatically as the user types.
Built-in tools: ClearButtonTool (auto-shows ✕ when text present), TextEntryStepperTool (increment/decrement numeric values), TextEntrySpeechToTextTool (voice input, in SpeechAddins package).
Stepper Tool:
<shiny:TextEntry Placeholder="Quantity"
Text="{Binding Quantity, Mode=TwoWay}"
Keyboard="Numeric">
<shiny:TextEntry.LeftTools>
<shiny:TextEntryStepperTool Step="-1" />
</shiny:TextEntry.LeftTools>
<shiny:TextEntryStepperTool Step="1" />
</shiny:TextEntry>TextEntryStepperTool increments or decrements the numeric text value by Step on each tap. If Text is not set, it auto-displays the step value with sign (e.g. "+1", "-5").
A slider control with a two-color gradient track, blended thumb border, tooltip, and full drag/tap interaction.
<shiny:Slider Value="{Binding Temperature}"
Minimum="0"
Maximum="100"
ColdColor="#3B82F6"
HotColor="#EF4444"
ShowTooltip="True" />| Property | Type | Default | Description |
|---|---|---|---|
| Value | double | 0 | Current value (TwoWay) |
| Minimum | double | 0 | Minimum value |
| Maximum | double | 100 | Maximum value |
| Step | double | 1 | Snap increment |
| ColdColor | Color/string | #3B82F6 | Left gradient color |
| HotColor | Color/string | #EF4444 | Right gradient color |
| TrackHeight | double | 8 | Track height |
| ThumbSize | double | 24 | Thumb diameter |
| ThumbColor | Color/string | White | Thumb fill color |
| ShowTooltip | bool | true | Show value tooltip |
| TooltipTemplate | DataTemplate/RenderFragment | null | Custom tooltip content |
| ValueFormat | string? | null | Format string for tooltip value |
A progress bar control with gradient fill and a configurable Vista-style shimmer pulse that sweeps left-to-right across the bar. Supports determinate, indeterminate, text overlay, and timed/value-triggered pulse animations.
<shiny:ProgressBar Value="{Binding Progress}"
TrackHeight="12"
CornerRadius="6"
UseGradient="True"
GradientStartColor="#3B82F6"
GradientEndColor="#8B5CF6"
PulseEnabled="True"
PulseOnValueChange="True"
PulseLength="0.4"
PulseSpeed="800" />| Property | Type | Default | Description |
|---|---|---|---|
| Value | double | 0 | Current value (TwoWay) |
| Minimum | double | 0 | Minimum value |
| Maximum | double | 100 | Maximum value |
| TrackColor | Color/string | #E5E7EB | Background track color |
| BarColor | Color/string | #3B82F6 | Fill bar color (when gradient disabled) |
| TrackHeight | double | 8 | Track height in px |
| CornerRadius | double/string | 4 | Corner radius |
| UseGradient | bool | false | Enable gradient fill |
| GradientStartColor | Color/string | #3B82F6 | Left gradient color |
| GradientEndColor | Color/string | #8B5CF6 | Right gradient color |
| PulseEnabled | bool | false | Enable Vista-style shimmer pulse |
| PulseOnValueChange | bool | true | Trigger pulse on value change |
| PulseInterval | TimeSpan | 0 | Trigger pulse on a timer (e.g. every 2s) |
| PulseColor | Color/string | White | Shimmer highlight color |
| PulseOpacity | double | 0.4 | Peak shimmer opacity (MAUI) |
| PulseLength | double | 0.4 | Width of shimmer as fraction of fill (0.05–1.0) |
| PulseSpeed | int | 800 | Milliseconds for one left-to-right sweep |
| ShowText | bool | false | Show percentage text overlay |
| TextFormat | string | "{0:0}%" | Text format string |
| TextColor | Color/string | White | Text color |
| FontSize | double | 11 | Text font size |
| IsIndeterminate | bool | false | Indeterminate sliding animation |
Events: ValueChangedEvent. Commands: ValueChangedCommand.
Full-screen overlay controls. On MAUI, integrates with OverlayHost/ShinyContentPage (same backdrop system as FloatingPanel). On Blazor, wraps content with a CSS-based overlay. Supports optional frosted glass blur effect.
MAUI (placed in ShinyContentPage.Panels):
<shiny:ShinyContentPage ...>
<ScrollView>...</ScrollView>
<shiny:ShinyContentPage.Panels>
<shiny:Overlay IsShown="{Binding IsOverlayVisible}" BlurRadius="10">
<shiny:Overlay.OverlayContentTemplate>
<DataTemplate>
<Label Text="Custom content" TextColor="White" />
</DataTemplate>
</shiny:Overlay.OverlayContentTemplate>
</shiny:Overlay>
<shiny:LoadingOverlay IsShown="{Binding IsBusy}"
Message="Loading..." />
</shiny:ShinyContentPage.Panels>
</shiny:ShinyContentPage>| Property | Type | Default | Description |
|---|---|---|---|
| IsShown | bool | false | Show/hide overlay (TwoWay) |
| AnimationDuration | uint | 250 | Fade animation duration in ms (MAUI) |
| BlurRadius | double | 0 | When > 0, applies a frosted glass blur behind the backdrop (MAUI uses FrostedGlassView; Blazor uses CSS backdrop-filter) |
| OverlayContentTemplate | DataTemplate | null | Custom overlay content (MAUI) |
| OverlayContent | RenderFragment | null | Custom overlay content (Blazor) |
MAUI backdrop color/opacity are controlled by ShinyContentPage.BackdropColor / BackdropMaxOpacity.
LoadingOverlay additional properties:
| Property | Type | Default | Description |
|---|---|---|---|
| IsIndeterminate | bool | true | Spinner mode (true) or progress bar mode (false) |
| Progress | double | 0 | Progress value 0–100 (when determinate) |
| Message | string? | null | Text displayed below spinner/progress bar |
| SpinnerColor | Color/string | White | Spinner color |
Blazor (wrapper pattern):
<LoadingOverlay IsShown="@isBusy" BlurRadius="8" IsIndeterminate="false" Progress="@progress" Message="Loading...">
<p>Your page content here — gets overlaid when IsShown=true</p>
</LoadingOverlay>A text input with debounced search, dropdown suggestions, busy indicator, and custom item templates. Supports both local filtering and remote search via a command/callback. Available on both MAUI and Blazor with full styling control.
<shiny:AutoCompleteEntry
Text="{Binding SearchText}"
Placeholder="Search..."
ItemsSource="{Binding Results}"
SelectedItem="{Binding SelectedResult}"
SearchCommand="{Binding SearchCommand}"
TextMemberPath="Name"
DebounceInterval="300"
Threshold="2"
MaxDropDownHeight="250"
FontSize="16"
TextColor="Black"
DropDownBackgroundColor="White"
DropDownBorderColor="LightGray"
CornerRadius="8" />| Property | Type | Default | Description |
|---|---|---|---|
| Text | string | "" | Current text value (TwoWay) |
| Placeholder | string? | null | Placeholder text |
| PlaceholderColor | Color/string | null | Placeholder text color |
| ItemsSource | IList | null | Suggestion items |
| SelectedItem | object? | null | Currently selected item (TwoWay) |
| SearchCommand | ICommand / EventCallback<string> | null | Remote search command |
| TextMemberPath | string? | null | Property name to display from items |
| ItemTemplate | DataTemplate / RenderFragment<object> | null | Custom dropdown item template |
| IsBusy | bool | false | Show/hide the loading spinner (TwoWay) |
| DebounceInterval | int | 300 | Debounce delay (ms) |
| Threshold | int | 1 | Minimum characters before searching |
| MaxDropDownHeight | double | 200 | Maximum dropdown height (px) |
| TextColor | Color/string | null | Input text color |
| FontSize | double | 14 | Input font size |
| FontFamily | string? | null | Input font family (MAUI only) |
| FontAttributes | FontAttributes | None | Bold/italic (MAUI only) |
| DropDownBackgroundColor | Color/string | White | Dropdown background |
| DropDownBorderColor | Color/string | LightGray | Dropdown border color |
| CornerRadius | double | 4 | Dropdown border radius (MAUI only) |
| SpinnerColor | Color/string | Grey | Loading spinner color |
| CssClass | string? | null | Root CSS class (Blazor only) |
| InputClass | string? | null | Input element CSS class (Blazor only) |
| DropDownClass | string? | null | Dropdown CSS class (Blazor only) |
| AdditionalAttributes | IDictionary | null | Unmatched HTML attributes (Blazor only) |
Events: ItemSelected fires when a suggestion is chosen.
Blazor CSS Custom Properties — Override these on a parent element or the component itself to theme without parameters:
| Variable | Default | Controls |
|---|---|---|
--shiny-ac-text |
inherit | Input text color |
--shiny-ac-ph |
#9CA3AF | Placeholder color |
--shiny-ac-dd-bg |
#fff | Dropdown background |
--shiny-ac-dd-border |
#D1D5DB | Dropdown border |
--shiny-ac-spinner |
#9CA3AF | Spinner color |
--shiny-ac-font-size |
inherit | Input font size |
--shiny-ac-dd-max-h |
200px | Dropdown max height |
A country search control built on AutoCompleteEntry with flag emoji display, country name, and dial code. Searches all ISO 3166-1 countries.
| Empty | With Selection |
|---|---|
![]() |
![]() |
<shiny:CountryPicker SelectedCountry="{Binding Country}"
Placeholder="Select country..."
FontSize="16"
TextColor="Black" />| Property | Type | Default | Description |
|---|---|---|---|
| SelectedCountry | Country | null | Selected country (TwoWay) |
| Placeholder | string | "Search countries..." | Placeholder text |
| MaxDropDownHeight | double | 200 | Max dropdown height |
| TextColor | Color/string | null | Text color |
| PlaceholderColor | Color/string | null | Placeholder color |
| DropDownBackgroundColor | Color/string | null | Dropdown background |
| DropDownBorderColor | Color/string | null | Dropdown border color |
| FontSize | double | 14 | Font size |
| FontFamily | string? | null | Font family (MAUI only) |
| CornerRadius | double | 4 | Dropdown corner radius (MAUI only) |
| InputClass | string? | null | Input CSS class (Blazor only) |
| DropDownClass | string? | null | Dropdown CSS class (Blazor only) |
Events: CountrySelected fires when a country is chosen.
The Country model provides: Name, Iso2, Iso3, DialCode, FlagEmoji.
An address search control built on AutoCompleteEntry that queries a geocoding provider (Nominatim/OpenStreetMap by default). Returns structured address data with coordinates.
<shiny:AddressEntry SelectedAddress="{Binding Address}"
Placeholder="Search address..."
CountryCodes="us,ca"
FontSize="16" />| Property | Type | Default | Description |
|---|---|---|---|
| SelectedAddress | Address | null | Selected address (TwoWay) |
| SearchProvider | IAddressSearchProvider? | null | Custom search provider (defaults to Nominatim) |
| CountryCodes | string? | null | Comma-separated ISO country codes to filter results |
| Placeholder | string | "Search address..." | Placeholder text |
| MaxDropDownHeight | double | 250 | Max dropdown height |
| TextColor | Color/string | null | Text color |
| PlaceholderColor | Color/string | null | Placeholder color |
| DropDownBackgroundColor | Color/string | null | Dropdown background |
| DropDownBorderColor | Color/string | null | Dropdown border color |
| FontSize | double | 14 | Font size |
| FontFamily | string? | null | Font family (MAUI only) |
| CornerRadius | double | 4 | Dropdown corner radius (MAUI only) |
| InputClass | string? | null | Input CSS class (Blazor only) |
| DropDownClass | string? | null | Dropdown CSS class (Blazor only) |
Events: AddressSelected fires when an address is chosen.
The Address record provides: DisplayName, HouseNumber, Street, City, State, PostalCode, Country, CountryCode, Latitude, Longitude.
Implement IAddressSearchProvider for custom geocoding:
public class MyGeoProvider : IAddressSearchProvider
{
public Task<IList<Address>> SearchAsync(string query, string? countryCodes, CancellationToken ct)
{
// call your preferred geocoding API
}
}Pill/chip/tag elements for displaying categories, filters, or status indicators with predefined or custom color schemes.
<shiny:PillView Text="Success" Type="Success" />
<shiny:PillView Text="Warning" Type="Warning" />
<shiny:PillView Text="Custom" PillColor="Purple" PillTextColor="White" />| Pill Type | Description |
|---|---|
| None | Default/neutral |
| Success | Green |
| Info | Blue |
| Warning | Yellow |
| Caution | Orange |
| Critical | Red |
Each PillType maps to a well-known style key (e.g. ShinyPillSuccessStyle) that can be overridden in your app's ResourceDictionary to customize the preset themes.
A Material Design-style floating action button, plus an expanding multi-action menu that animates up from the main FAB.
| Closed | Menu Open |
|---|---|
![]() |
![]() |
<!-- Single Fab -->
<shiny:Fab Icon="add.png"
Text="Add Item"
FabBackgroundColor="#4CAF50"
TextColor="White"
Command="{Binding AddCommand}"
HorizontalOptions="End"
VerticalOptions="End"
Margin="24" />
<!-- FabMenu with child items -->
<shiny:FabMenu IsOpen="{Binding IsMenuOpen}"
Icon="plus.png"
FabBackgroundColor="#2196F3"
HorizontalOptions="End"
VerticalOptions="End"
Margin="24">
<shiny:FabMenuItem Icon="share.png" Text="Share" Command="{Binding ShareCommand}" />
<shiny:FabMenuItem Icon="edit.png" Text="Edit" Command="{Binding EditCommand}" />
<shiny:FabMenuItem Icon="delete.png" Text="Delete" Command="{Binding DeleteCommand}" />
</shiny:FabMenu>Fab properties:
| Property | Type | Default | Description |
|---|---|---|---|
| Icon | ImageSource? | null | Button icon |
| Text | string? | null | Optional label; when null the Fab is a perfect circle |
| Command | ICommand? | null | Invoked when the Fab is tapped |
| CommandParameter | object? | null | Parameter passed to the Command |
| FabBackgroundColor | Color | #2196F3 | Fill color |
| BorderColor | Color? | null | Outline stroke color |
| BorderThickness | double | 0 | Outline stroke thickness |
| TextColor | Color | White | Label color |
| FontSize | double | 14 | Label font size |
| FontAttributes | FontAttributes | None | Label font attributes |
| Size | double | 56 | Height of the Fab (diameter when circular) |
| IconSize | double | 24 | Icon image size |
| HasShadow | bool | true | Show drop shadow |
| UseFeedback | bool | true | Feedback on tap |
Events: Clicked.
FabMenu properties (plus all main-Fab pass-throughs above):
| Property | Type | Default | Description |
|---|---|---|---|
| IsOpen | bool | false | Two-way bindable; opens/closes the menu with animation |
| Items | IList<FabMenuItem> |
empty | Menu items (content property — place items directly inside the FabMenu) |
| FabSize | double | 56 | Main FAB button size (diameter) |
| HasShadow | bool | true | Drop shadow on the main FAB |
| MenuAlignment | LayoutOptions | End | Horizontal alignment of the menu stack (Start for left-aligned, End for right-aligned) |
| HasBackdrop | bool | true | Show a dim backdrop while open |
| BackdropColor | Color | Black | Backdrop color |
| BackdropOpacity | double | 0.4 | Backdrop peak opacity |
| CloseOnBackdropTap | bool | true | Close when backdrop is tapped |
| CloseOnItemTap | bool | true | Close after any item is tapped |
| AnimationDuration | uint | 200 | Open/close animation duration (ms) |
| UseFeedback | bool | true | Feedback on toggle |
Events: ItemTapped — fires the FabMenuItem that was tapped.
Methods: Open(), Close(), Toggle().
FabMenuItem properties:
| Property | Type | Default | Description |
|---|---|---|---|
| Icon | ImageSource? | null | Circular icon |
| Text | string? | null | Side label next to the icon |
| Command | ICommand? | null | Invoked when tapped |
| CommandParameter | object? | null | Parameter for the Command |
| FabBackgroundColor | Color | #2196F3 | Icon button fill |
| BorderColor | Color? | null | Icon button outline |
| BorderThickness | double | 0 | Icon button outline thickness |
| TextColor | Color | Black | Side-label text color |
| LabelBackgroundColor | Color | White | Side-label background |
| FontSize | double | 13 | Side-label font size |
| Size | double | 44 | Icon button diameter |
| IconSize | double | 20 | Icon image size |
| UseFeedback | bool | true | Feedback on tap |
Placement tip: FabMenu should live in a Grid that fills the page (the same placement pattern as ImageViewer) so the backdrop can cover the page content. Alternatively, use ShinyContentPage with OverlayHost for easier overlay management.
A PIN entry control with individually rendered cells that captures input through a hidden Entry. Digits remain visible by default and can optionally be masked with any character.
<shiny:SecurityPin Length="4"
HideCharacter="*"
Value="{Binding Pin}"
Keyboard="Numeric"
Completed="OnPinCompleted" />| Property | Type | Default | Description |
|---|---|---|---|
| Length | int | 4 | Number of PIN cells |
| Value | string | "" | Current PIN value (TwoWay) |
| Keyboard | Keyboard | Numeric | Keyboard type for input |
| HideCharacter | string? | null | When set, masks entered characters; when null/empty, shows actual values |
| CellSize | double | 50 | Width/height of each cell |
| CellSpacing | double | 8 | Space between cells |
| CellCornerRadius | double | 8 | Border corner radius |
| CellBorderColor | Color? | null | Cell border color |
| CellFocusedBorderColor | Color? | null | Border color for the active cell |
| CellBackgroundColor | Color? | null | Cell fill color |
| CellTextColor | Color? | null | Entered character color |
| FontSize | double | 24 | Character font size |
| UseFeedback | bool | Enable/disable feedback on digit entry (click) and completion (long press) (default: true) |
Events: Completed fires with a SecurityPinCompletedEventArgs once the entered value reaches Length.
Methods: Focus(), Unfocus(), Clear().
A signature capture control that opens in a FloatingPanel overlay (MAUI) or SheetView (Blazor). Users draw on a canvas and tap Sign to export the signature as a PNG. The Sign button is disabled until the user actually draws something.
Important: Like FloatingPanel, SignaturePad must be placed inside an OverlayHost or ShinyContentPage on MAUI — it uses a FloatingPanel internally.
<!-- MAUI — must be inside ShinyContentPage.Panels or OverlayHost -->
<shiny:ShinyContentPage xmlns:shiny="http://shiny.net/maui/controls">
<shiny:ShinyContentPage.PageContent>
<VerticalStackLayout Padding="20" Spacing="10">
<Button Text="Capture Signature" Command="{Binding OpenSignatureCommand}" />
<Image Source="{Binding SignatureImage}" HeightRequest="150" Aspect="AspectFit" />
</VerticalStackLayout>
</shiny:ShinyContentPage.PageContent>
<shiny:ShinyContentPage.Panels>
<shiny:SignaturePad IsOpen="{Binding IsSignatureOpen}"
StrokeColor="Black"
SignatureBackgroundColor="#F8F8F8"
StrokeWidth="3"
SignButtonColor="#6C63FF"
CancelButtonColor="#94A3B8"
SignCommand="{Binding HandleSignedCommand}"
CancelCommand="{Binding HandleCancelledCommand}" />
</shiny:ShinyContentPage.Panels>
</shiny:ShinyContentPage><!-- Blazor -->
<SignaturePad @bind-IsOpen="isOpen"
StrokeColor="#000000"
SignatureBackgroundColor="#F8F8F8"
StrokeWidth="3"
SignButtonColor="#6C63FF"
CancelButtonColor="#94A3B8"
Signed="OnSigned"
Cancelled="OnCancelled" />| Property | Type | Default | Description |
|---|---|---|---|
| IsOpen | bool | false | Opens/closes the signature panel (TwoWay) |
| Position | FloatingPanelPosition | Bottom | Panel slide direction (Bottom, BottomTabs, Top) |
| IsLocked | bool | true | Prevents drag dismiss |
| Detent | DetentValue | Half | Panel snap position |
| StrokeColor | Color | Black | Drawing stroke color |
| SignatureBackgroundColor | Color | White | Canvas background |
| StrokeWidth | double | 3.0 | Drawing stroke width |
| SignButtonText | string | "Sign" | Sign button label |
| CancelButtonText | string | "Cancel" | Cancel button label |
| SignButtonColor | Color | Blue | Sign button background |
| CancelButtonColor | Color | Gray | Cancel button background |
| ShowCancelButton | bool | true | Show/hide cancel button |
| PanelBackgroundColor | Color | White | Panel background |
| PanelCornerRadius | double | 16 | Panel corner radius |
| HasBackdrop | bool | true | Backdrop behind panel |
| ExportWidth | int | 600 | Exported PNG width |
| ExportHeight | int | 200 | Exported PNG height |
| SignCommand | ICommand? | null | Invoked on sign with SignatureImageEventArgs |
| CancelCommand | ICommand? | null | Invoked on cancel |
Blazor uses CSS color strings instead of Color, SheetDirection instead of FloatingPanelPosition, and Signed is EventCallback<byte[]> (raw PNG bytes).
Events: Signed fires with SignatureImageEventArgs (MAUI) or byte[] (Blazor). Cancelled fires on cancel.
A view that applies a native frosted glass (blur) effect behind its content. Place over images or busy backgrounds for a glassmorphism effect.
<shiny:FrostedGlassView BlurRadius="20"
TintColor="#80FFFFFF"
TintOpacity="0.6"
CornerRadius="16">
<VerticalStackLayout Padding="20" Spacing="8">
<Label Text="Glass Card" FontSize="20" FontAttributes="Bold" />
<Label Text="Content over blurred background." FontSize="14" />
</VerticalStackLayout>
</shiny:FrostedGlassView><!-- Blazor -->
<FrostedGlass BlurRadius="20" TintColor="rgba(255,255,255,0.6)" CornerRadius="16">
<h3>Glass Card</h3>
<p>Content over blurred background.</p>
</FrostedGlass>| Property | Type | Default | Description |
|---|---|---|---|
| GlassContent / ChildContent | View / RenderFragment | - | Content rendered on top of the glass |
| BlurRadius | double | 20 | Blur strength in pixels |
| TintColor | Color / string | #80FFFFFF / rgba(255,255,255,0.6) | Glass tint overlay |
| TintOpacity | double | 0.6 | Tint opacity (MAUI only) |
| CornerRadius | double | 0 | Corner radius for clipping |
Platform implementation: iOS uses UIVisualEffectView, Android 12+ uses RenderEffect.CreateBlurEffect, Blazor uses CSS backdrop-filter: blur().
A service-first toast notification system — inject IToaster (registered by UseShinyControls()) and call from code. No XAML or OverlayHost required. The overlay auto-attaches to the current page on first use.
using Shiny.Maui.Controls.Toast;
public class MyViewModel(IToaster toaster)
{
// Simple
await toaster.ShowAsync("Item saved!");
// With spinner + manual dismiss
IDisposable toast = await toaster.ShowAsync("Uploading...", cfg =>
{
cfg.Spinner = ToastSpinnerPosition.Left;
cfg.Duration = TimeSpan.Zero;
});
// Later: toast.Dispose();
}Themed methods — colors from MAUI Styles or built-in defaults:
await toaster.InfoAsync("Update available"); // Blue
await toaster.SuccessAsync("File saved"); // Green
await toaster.WarningAsync("Storage almost full"); // Amber
await toaster.DangerAsync("Save failed"); // Orange
await toaster.CriticalAsync("System error"); // Red<!-- Blazor: register AddShinyToast() in DI, place <ToastHost /> in layout -->
@inject IToastService ToastService
await ToastService.ShowAsync("Saved!", cfg =>
{
cfg.Duration = TimeSpan.FromSeconds(3);
cfg.ShowProgressBar = true;
});
// Blazor themed methods also available:
await ToastService.InfoAsync("Update available");
await ToastService.SuccessAsync("File saved");| Property | Type | Default | Description |
|---|---|---|---|
| Text | string | (required) | Toast message |
| Duration | TimeSpan | 3s | Auto-dismiss. Zero = manual only |
| Position | ToastPosition | Bottom | Top or Bottom |
| DisplayMode | ToastDisplayMode | Pill | Pill (rounded) or FillHorizontal (full width) |
| DismissOnTap | bool | true | Tap to dismiss |
| QueueMode | ToastQueueMode | Queue | Queue (sequential) or Stack (multiple visible) |
| Spinner | ToastSpinnerPosition | None | None, Left, or Right |
| ShowProgressBar | bool | false | Countdown drain bar |
| Icon | ImageSource? | null | Optional icon (MAUI) |
| TapCommand | ICommand? | null | Tap action (MAUI) |
| UseFeedback | bool | true | Feedback on show/dismiss |
| BackgroundColor | Color? | dark gray | Background fill |
| TextColor | Color? | white | Text color |
| BorderColor | Color? | null | Border stroke |
| CornerRadius | double | 20 | Corner radius (pill mode) |
| TextOverflow | ToastTextOverflow | Ellipsis | Ellipsis, MultiLine, or Marquee |
| MarqueeSpeedPixelsPerSecond | double | 40 | Scroll speed for marquee mode |
Text Overflow modes:
Ellipsis— truncates long text with "…" (default)MultiLine— wraps text to multiple linesMarquee— scrolling ticker animation (configure speed viaMarqueeSpeedPixelsPerSecond)
A settings-style table view with 14+ built-in cell types, section grouping, drag-to-reorder, and dynamic data binding.
| Basic | Dynamic | Drag & Sort | Pickers | Styling |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
<shiny:TableView>
<shiny:TableRoot>
<shiny:TableSection Title="General">
<shiny:SwitchCell Title="Wi-Fi" On="{Binding WifiEnabled}" />
<shiny:EntryCell Title="Username" Text="{Binding Username}" />
<shiny:PickerCell Title="Theme" ItemsSource="{Binding Themes}" SelectedItem="{Binding SelectedTheme}" />
</shiny:TableSection>
</shiny:TableRoot>
</shiny:TableView>Cell Types:
| Cell | Description |
|---|---|
| SwitchCell | Toggle switch |
| EntryCell | Text input field |
| CheckboxCell | Checkbox with accent color |
| RadioCell | Radio button with section-level grouping |
| CommandCell | Tappable row with optional arrow indicator |
| ButtonCell | Command-bound button |
| LabelCell | Read-only text display |
| PickerCell | Single or multi-select picker |
| TextPickerCell | String list picker |
| DatePickerCell | Date selection with min/max bounds |
| TimePickerCell | Time selection with 24-hour mode and minute interval |
| DurationPickerCell | TimeSpan picker with min/max |
| NumberPickerCell | Integer picker with min/max/unit |
| SimpleCheckCell | Checkmark indicator |
| CustomCell | Custom view content with drag-reorder support |
Dynamic Sections - Bind to a collection to generate sections from data:
<shiny:TableView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource SectionTemplate}" />Separate NuGet packages:
Shiny.Maui.Controls.Markdown/Shiny.Blazor.Controls.Markdown
Render and edit markdown content using native MAUI controls — no WebView required on MAUI. Auto-resolves Light/Dark theming. Available for both MAUI and Blazor.
| Viewer | Editor |
|---|---|
![]() |
![]() |
MarkdownView — Read-only markdown renderer:
<md:MarkdownView Markdown="{Binding DocumentContent}" Padding="16" />| Property | Type | Description |
|---|---|---|
| Markdown | string | Markdown content to render |
| Theme | MarkdownTheme? | Rendering theme (auto Light/Dark if null) |
| IsScrollEnabled | bool | Enable/disable scrolling (default: true) |
Events: LinkTapped — fired when a link is tapped; set Handled = true to prevent default browser launch.
MarkdownEditor — Editor with formatting toolbar and live preview:
<md:MarkdownEditor Markdown="{Binding NoteContent, Mode=TwoWay}"
Placeholder="Start writing..."
Padding="8" />| Property | Type | Description |
|---|---|---|
| Markdown | string | Markdown content (TwoWay) |
| Theme | MarkdownTheme? | Preview theme (auto Light/Dark if null) |
| Placeholder | string | Placeholder text |
| ToolbarItems | IReadOnlyList<MarkdownToolbarItem>? | Toolbar buttons (default set provided) |
| IsPreviewVisible | bool | Toggle preview pane (TwoWay) |
| ToolbarBackgroundColor | Color? | Toolbar background |
| EditorBackgroundColor | Color? | Editor background |
Features:
- Formatting toolbar: bold, italic, headings, lists, code, links, blockquotes
- Live preview toggle
- Auto-growing editor
- Full Markdig support: tables, task lists, strikethrough, fenced code blocks
- Customizable themes with colors, font sizes, and spacing
- Custom toolbar item support
Separate NuGet packages:
Shiny.Maui.Controls.MermaidDiagrams/Shiny.Blazor.Controls.MermaidDiagrams
Native Mermaid flowchart renderer — no WebView, no SkiaSharp, AOT compatible on MAUI. Parses Mermaid syntax and renders interactive diagrams with pan and zoom support. Available for both MAUI and Blazor.
| Flowchart | Editor | Themes | Subgraphs |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
dotnet add package Shiny.Maui.Controls.MermaidDiagramsxmlns:diagram="http://shiny.net/maui/diagrams"<diagram:MermaidDiagramControl
DiagramText="graph TD A[Start] --> B{Decision} B -->|Yes| C[Do Something] B -->|No| D[Do Other] C --> E[End] D --> E"
HorizontalOptions="Fill"
VerticalOptions="Fill" />Features:
- Mermaid
graph/flowchartsyntax (TD, LR, BT, RL directions) - 6 node shapes: Rectangle, RoundedRectangle, Stadium, Circle, Diamond, Hexagon
- 6 edge styles: Solid, Open, Dotted, DottedOpen, Thick, ThickOpen
- Subgraph support with nested grouping
- 4 built-in themes: Default, Dark, Forest, Neutral
- Pan and pinch-to-zoom gestures
- Sugiyama layered graph layout algorithm
A Netflix-style horizontal carousel with snap-to-center behavior, configurable scale transforms for focused/unfocused items, peek area insets, and position tracking. Uses native platform recycler views on MAUI (Android RecyclerView, iOS UICollectionView, Windows ItemsRepeater) and CSS scroll-snap on Blazor.
<shiny:CarouselGallery ItemsSource="{Binding Items}"
ItemWidth="280"
ItemHeight="160"
ItemSpacing="16"
PeekAreaInsets="40"
FocusedItemScale="1.0"
UnfocusedItemScale="0.85"
CurrentPosition="{Binding Position}"
ItemSelectedCommand="{Binding SelectCommand}"
HeightRequest="180">
<shiny:CarouselGallery.ItemTemplate>
<DataTemplate>
<Border BackgroundColor="{Binding Color}" StrokeThickness="0">
<Label Text="{Binding Title}" TextColor="White" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" />
</Border>
</DataTemplate>
</shiny:CarouselGallery.ItemTemplate>
</shiny:CarouselGallery>| Property | Type | Default | Description |
|---|---|---|---|
FocusedItemScale |
double |
1.0 |
Scale of the centered item |
UnfocusedItemScale |
double |
0.8 |
Scale of off-center items |
ItemWidth |
double |
required | Width of each carousel item |
ItemHeight |
double |
required | Height of each carousel item |
CurrentPosition |
int |
0 |
Current centered item index (TwoWay) |
PeekAreaInsets |
Thickness |
0 |
Visible area of adjacent items |
IsInfinite |
bool |
false |
Enable infinite loop scrolling |
SnapCount |
int |
1 |
Number of items to snap into view at once. Set to 0 for free-scroll (Netflix-style) with no snapping |
PositionChangedCommand |
ICommand |
null |
Fires when position changes |
Features:
- Snap-to-center with smooth deceleration (configurable via
SnapCount) - Free-scroll mode (
SnapCount="0") for Netflix-style browsing without snapping - Scale transforms for focused/unfocused items
- Peek area insets to show adjacent items
- Two-way position binding
- Infinite loop mode (MAUI)
- Dot indicators (Blazor)
A Pinterest-style masonry/waterfall layout that arranges variable-height items in columns. Uses native staggered layout managers on MAUI (Android StaggeredGridLayoutManager, iOS custom WaterfallLayout, Windows WaterfallVirtualizingLayout) and CSS column-count on Blazor.
<shiny:StaggeredGrid ItemsSource="{Binding Items}"
ColumnCount="3"
ColumnSpacing="12"
RowSpacing="12"
ItemSelectedCommand="{Binding SelectCommand}">
<shiny:StaggeredGrid.ItemTemplate>
<DataTemplate>
<Border BackgroundColor="{Binding Color}" HeightRequest="{Binding Height}" StrokeThickness="0">
<Label Text="{Binding Title}" TextColor="White" Padding="12" />
</Border>
</DataTemplate>
</shiny:StaggeredGrid.ItemTemplate>
</shiny:StaggeredGrid>| Property | Type | Default | Description |
|---|---|---|---|
ColumnCount |
int |
2 |
Number of columns (minimum 1) |
ColumnSpacing |
double |
0 |
Horizontal gap between columns |
RowSpacing |
double |
0 |
Vertical gap between items |
Inherits all CollectionControlBase properties: ItemsSource, ItemTemplate, ItemTemplateSelector, HeaderTemplate, FooterTemplate, EmptyViewTemplate, ItemSelectedCommand, LoadMoreCommand, LoadMoreThreshold, ItemSpacing.
A full-featured grouped grid with sticky section headers, virtualization, orientation-aware column counts, load-more, and cell padding. Uses native grid layouts on MAUI (Android GridLayoutManager with StickyHeaderDecoration, iOS UICollectionViewCompositionalLayout with pinned headers, Windows ItemsRepeater with UniformGridLayout) and CSS Grid with Blazor Virtualize<T> on Blazor.
<shiny:VirtualizedGrid ItemsSource="{Binding Items}"
ColumnCount="3"
ItemSpacing="8"
CellPadding="4"
IsGroupingEnabled="True"
HasStickyHeaders="True"
ItemSelectedCommand="{Binding SelectCommand}">
<shiny:VirtualizedGrid.GroupHeaderTemplate>
<DataTemplate>
<Label Text="{Binding .}" FontAttributes="Bold" Padding="8,4" />
</DataTemplate>
</shiny:VirtualizedGrid.GroupHeaderTemplate>
<shiny:VirtualizedGrid.ItemTemplate>
<DataTemplate>
<Border BackgroundColor="{Binding Color}" StrokeThickness="0" Padding="12">
<Label Text="{Binding Name}" TextColor="White" HorizontalTextAlignment="Center" />
</Border>
</DataTemplate>
</shiny:VirtualizedGrid.ItemTemplate>
</shiny:VirtualizedGrid>| Property | Type | Default | Description |
|---|---|---|---|
ColumnCount |
int |
1 |
Number of grid columns |
PortraitColumnCount |
int? |
null |
Column count in portrait (uses ColumnCount if null) |
LandscapeColumnCount |
int? |
null |
Column count in landscape (uses ColumnCount if null) |
IsGroupingEnabled |
bool |
false |
Enable grouped layout with section headers |
GroupHeaderTemplate |
DataTemplate |
null |
Template for group headers |
HasStickyHeaders |
bool |
true |
Pin group headers while scrolling |
CellPadding |
Thickness |
0 |
Padding inside each cell |
ShowLoadMoreButton |
bool |
false |
Show a load-more button at the end of the data |
LoadMoreButtonTemplate |
DataTemplate |
null |
Custom load-more button template; defaults to a centered "Load More" button |
IsLoadingMore |
bool |
false |
Loading state (OneWayToSource) |
ItemVisibleCommand |
ICommand |
null |
Fires when an item becomes visible |
ItemHiddenCommand |
ICommand |
null |
Fires when an item scrolls out of view |
Inherits all CollectionControlBase properties: ItemsSource, ItemTemplate, ItemTemplateSelector, HeaderTemplate, FooterTemplate, EmptyViewTemplate, ItemSelectedCommand, LoadMoreCommand, LoadMoreThreshold, ItemSpacing.
Features:
- Grouped data with sticky section headers that pin while scrolling
- Orientation-aware column count (portrait vs landscape)
- Built-in load-more button with loading state
- Item visibility tracking for analytics or lazy loading
- Full header, footer, and empty view templates

































