Skip to content
Client v5: BLE, BLE Hosting, HTTP, Jobs - Linux, MacOS, & Blazor Support! Full AOT, RX on BLE only & MANY other features! Power up!

Controls Releases

Release notes for the MAUI packages (Shiny.Maui.Controls, Shiny.Maui.Controls.Markdown, Shiny.Maui.Controls.MermaidDiagrams) and the Blazor packages (Shiny.Blazor.Controls, Shiny.Blazor.Controls.Markdown, Shiny.Blazor.Controls.MermaidDiagrams).

Feature
CameraView — AI document scanner — New Shiny.Maui.Controls.Camera.Ai and Shiny.Blazor.Controls.Camera.Ai packages add an AI-backed document scanner that splits detection from extraction to save time and cost: a cheap presence detector runs every frame (Apple Vision document segmentation / managed edge detection on MAUI; an in-browser luminance heuristic on Blazor — no OCR) and draws a live outline, but the model is called at most once per document — only when one is held steady and the analyzer is armed. At that point it encodes just that frame to JPEG (cropped to the document) and sends it to a Microsoft.Extensions.AI IChatClient, parsing the reply into your type via MEAI structured output. MAUI exposes AiDocumentAnalyzer<TDocument> (and a zero-setup AiDocumentAnalyzer returning the schema-free AiDocument); Blazor exposes AiDocumentScanner<TDocument> driving the new DocumentAnalyzer + CameraView.RequestDocumentImageAsync. Provider-agnostic (Azure OpenAI / OpenAI / Ollama / …), trim/AOT-friendly, and the model call runs off the analysis thread so the preview never stalls. TODO: capture screenshots for the AI document scanner. (MAUI + Blazor)
Feature
AI Prompt — New Siri-style full-screen AI entry overlay (AiPromptOverlay + IAiPromptService) on MAUI and Blazor: a frosted/blurred backdrop, an animated multi-colour glow that runs around the screen edge (default Siri-style violet → pink → blue → teal, a GraphicsView/IDrawable ring on MAUI and an animated CSS conic-gradient border on Blazor — no icon-font or image dependency), and a large “Ask anything…” prompt entry with microphone + submit buttons. Use it declaratively (AiPromptOverlay with IsOpen/Submitted) or invoke IAiPromptService.PromptAsync(...) from code for an AiPromptResult. Speech-to-text is optional and decoupled via IAiPromptSpeechProvider — opt in with the SpeechAddins packages: .UseAiPromptSpeech() on MAUI (native speech, final transcript) or AddAiPromptSpeech() on Blazor (browser Web Speech API with live partial transcription). Colours follow the active Shiny theme tokens; the service auto-attaches its overlay (MAUI auto-registers via UseShinyControls(); Blazor needs AddShinyAiEntry() + a single <AiPromptHost />) (MAUI + Blazor)
Feature
CameraView — Business Card analyzer — New BusinessCardAnalyzer in Shiny.Maui.Controls.Camera.Documents reads a business card into a strongly-typed BusinessCard record: the cardholder Name + JobTitle, the Company, every contact channel (Emails and typed Phones, each tagged Mobile/Office/Fax… from its line label), Website, and a best-effort Address. Email / phone / URL are matched deterministically; name / title / company are heuristic. Like the other OCR-backed document analyzers it accumulates fields across frames, shares the one-pass OCR + deskew pipeline, and accepts a custom IDocumentParser<BusinessCard> (rules, cloud Document AI, or an LLM) for production accuracy (MAUI)
Feature
Dialogs — richer Prompt + optional cancel buttonIDialogService.Prompt now forwards initialValue, maxLength, and the keyboard directly (MAUI takes a Keyboard; Blazor takes an HTML inputType string), so you no longer have to reach into the configure delegate for common prompt setup. Prompt and ActionSheet now accept a nullable cancelText — pass cancelText: null to hide the cancel button entirely (previously the owned ActionSheet always rendered one). This makes IDialogService a clean drop-in when adapting Shiny.Framework’s IDialogs, whose cancel: null means “no cancel button” (MAUI + Blazor)
Fix
TextPickerCell — selection lost when a TableView section toggles — Selecting a value in a TextPickerCell that drives section visibility (e.g. a “Type” picker whose choice shows/hides other TableSections) blanked the cell and reverted the selection. Toggling section IsVisible re-renders the TableView, which re-attaches the cell and makes the native picker raise a spurious SelectedIndex = -1; that reset was written back to the bound SelectedIndex, clobbering it. The control now ignores the spurious reset and restores selection from either SelectedItem or SelectedIndex (previously only SelectedItem was honored, so SelectedIndex-only bindings lost their display) (MAUI)
Fix
SignaturePad — iOS edge swipe stole strokes — On iOS, signing near the left screen edge frequently triggered the navigation controller’s interactive “swipe back” pop gesture instead of drawing, so users couldn’t complete a signature that started at the edge. The control now disables that interactive pop gesture while the pad is open and restores it on close — no consumer code changes required (MAUI/iOS)
Fix
SignaturePad — Android edge swipe & tab swipe stole strokes — The same edge-stroke problem appeared on Android in two forms: the system back edge-swipe (gesture navigation, API 29+) hijacked strokes started near the left/right edges, and when the pad was hosted inside a TabbedPage a horizontal stroke swiped to the next/previous tab. While the pad is open the control now registers a system gesture-exclusion rect over the canvas and freezes the hosting TabbedPage’s ViewPager2, restoring both on close — no consumer code changes required (MAUI/Android)
Fix
Blazor DataGrid infinite render loop — Declaring a DataGrid<TItem> with columns could peg the browser in an endless render cycle: each column notified the grid (StateHasChanged) from its OnParametersSet, and the grid’s re-render re-rendered the columns, re-firing OnParametersSet — forever. Columns now re-notify the grid only when a layout-affecting parameter (Title, Hidden, Width, Sortable, sticky, etc.) actually changes, so genuine column edits still refresh the header while the steady state stays put (Blazor)
Feature
Initial consolidated release of Shiny.Maui.Controls
Feature
Blazor support — Every control ships as a matching Razor component in Shiny.Blazor.Controls, with Markdown and Mermaid Diagrams in their own Shiny.Blazor.Controls.Markdown and Shiny.Blazor.Controls.MermaidDiagrams packages. Drop them into any .razor page — no DI registration required, just @using directives
Feature
TableView — 14 built-in cell types, three-level cascading styles, drag-to-sort, dynamic sections with ItemTemplate, and full MVVM support (MAUI + Blazor)
Feature
DataGrid — A feature-rich data grid modeled on MudBlazor’s DataGrid. Blazor is a generic DataGrid&lt;TItem&gt; rendering a semantic HTML &lt;table&gt; with child PropertyColumn/TemplateColumn; MAUI is a pure cross-platform composite (shiny:DataGrid over a virtualized CollectionView, no native handlers). Typed + template columns, sorting (single/multi), column filtering (menu/row/toolbar quick-search), grouping with expandable groups, footer & group aggregates (Count/Sum/Average/Min/Max/Custom), single/multi selection with checkboxes, inline editing (cell + form), paging, virtualization, column resize & reorder, sticky header, loading + empty states, a ServerData delegate for server-side data, and density/striped/bordered/hover styling — all theme-token aware (MAUI + Blazor)
Feature
Scheduler — Calendar grid, agenda timeline, and event list views with ISchedulerEventProvider, custom templates, and AOT-safe bindings (MAUI + Blazor)
Feature
FloatingPanel — Draggable floating panel overlay (bottom, bottom with tabs, or top) with configurable detents, header peek when closed, backdrop dimming via OverlayHost, pan gestures, locked mode, fit-content auto-sizing, and keyboard handling. Includes ShinyContentPage convenience base class. Replaces the previous SheetView on MAUI (MAUI). Blazor retains SheetView as its equivalent component
Feature
PillView — Status badge with 6 preset themes (Success, Info, Warning, Caution, Critical), custom colors, and WCAG-accessible contrast (MAUI + Blazor)
Feature
SecurityPin — PIN entry control with individually rendered cells, optional character masking via HideCharacter, configurable length, cell sizing, colors, and keyboard type (MAUI + Blazor)
Feature
Fab & FabMenu — Material Design floating action button with circular or extended (icon + text) pill shapes, plus an expanding multi-action menu with staggered open/close animation, backdrop dimming, and two-way bindable IsOpen (MAUI + Blazor)
Feature
ImageViewer — Full-screen image overlay with pinch-to-zoom, pan when zoomed, double-tap to toggle zoom, and animated fade transitions (MAUI + Blazor)
Feature
ImageEditor — Inline image editor with cropping (drag-handle selection with dimmed overlay), rotation, freehand drawing with color, line and arrow drawing, text annotations with font family and font size selection, undo/redo stack, reset-to-original, and export to PNG/JPEG/WEBP at configurable resolutions. Every feature can be toggled on/off via properties, and the default toolbar is fully replaceable (MAUI + Blazor)
Feature
FontPicker — Font family selection control with inline list and popup button variants. Each font renders in its own typeface for instant preview. Includes FontSizePicker and FontSizePickerButton for size selection. Integrated into the ImageEditor toolbar (MAUI)
Feature
ChatView — Provider-driven chat UI. The control is styles + layout only; all data, lifecycle, permissions, and real-time behavior live behind an IChatSessionProvider you implement (the same model as the Scheduler). You bind a Provider + SessionId — no Messages collection, SendCommand, Participants, or bubble-tool tree. The provider hands the control a session-scoped IChatSession (Info, CurrentUserId, cursor-based GetMessagesAsync, SendMessageAsync/ResendMessageAsync/EditMessageAsync/DeleteMessageAsync, ReactToMessageAsync, MarkReadAsync, ToggleTypingAsync, InviteUserAsync/LeaveAsync/RenameAsync, and live events the control marshals to the UI thread). Features: permission-driven affordances via ChatSessionPermissions + ownership, cursor paging that stays stable under live inserts, optimistic send with reconcile-by-ClientMessageId and Failed (transient, retryable via ResendMessageAsync) vs Rejected (provider refused via ChatSendRejectedException, no retry) verdicts, emoji reactions filtered to PermittedEmojis (null => built-in default set; empty => none), per-user read receipts, a self-contained markdown composition toolbar gated by MessageBodyPermissions with inline bubble rendering (no Markdown-package dependency), image attachments from gallery or camera (where capture is supported) with tap-to-open the built-in ImageViewer, animated typing indicators, and a connection banner that disables input while offline. MAUI adds custom message templates (MessageTemplate/MessageTemplateSelector) and ChatInputAction/ChatBubbleAction hooks for app-specific verbs (SpeechToTextTool/TextToSpeechBubbleTool ship in Shiny.Maui.Controls.SpeechAddins). Validation belongs in the provider (ChatSessionException/ChatSendRejectedException). Still v1 beta (MAUI + Blazor)
Feature
AutoCompleteEntry — Text input with debounced search, dropdown suggestions, busy spinner, custom item templates, and configurable thresholds. Supports both local filtering and remote async search via SearchCommand (MAUI + Blazor)
Feature
AddressEntry — Address search control built on AutoCompleteEntry with geocoding via Nominatim/OpenStreetMap by default, structured Address results with coordinates, country code filtering, and pluggable IAddressSearchProvider for custom geocoding services (MAUI + Blazor)
Feature
CountryPicker — Country search control built on AutoCompleteEntry with flag emoji display, country name, dial code, and full ISO 3166-1 data. Instant local filtering across all countries (MAUI + Blazor)
Feature
ColorPicker & ColorPickerButton — Full-featured color picker with HSV spectrum, hue bar, optional opacity slider, hex input, and live preview swatch. Available as an inline ColorPicker or a ColorPickerButton that opens a popup dialog with auto-contrast text (MAUI + Blazor)
Feature
Markdown (separate package) — Read-only MarkdownView renderer and MarkdownEditor with formatting toolbar, live preview, and customizable themes (MAUI + Blazor)
Feature
Mermaid Diagrams (separate package) — Native Mermaid flowchart rendering with Sugiyama layout, 6 node shapes, 6 edge styles, subgraphs, 4 themes, and pan/zoom (MAUI + Blazor)
Feature
DurationPicker — Standalone duration picker control (DurationPicker) that opens a FloatingPanel with hour/minute selection, “hr”/“min” labels, min/max constraints, and configurable minute intervals. The DurationPickerCell TableView cell uses the same FloatingPanel-based picker internally. Requires ShinyContentPage (MAUI)
Feature
FrostedGlassView — A view that applies a native frosted glass (blur) effect behind its content. iOS/macCatalyst uses UIVisualEffectView with theme-aware UIBlurEffect for true real-time backdrop blur. Android 12+ captures the background behind the view and applies RenderEffect blur for per-view frosted glass. Blazor uses CSS backdrop-filter: blur(). Configurable blur radius, tint color/opacity, and corner radius. Falls back to semi-transparent tint on older Android (MAUI + Blazor)
Feature
TimePickerCell enhancementsUse24Hour property switches between 24-hour and AM/PM format; MinuteInterval constrains minute selection (iOS enforces natively via UIDatePicker.MinuteInterval, other platforms snap to nearest interval on selection) (MAUI)
Feature
Toast — Service-first toast notification system invoked via DI-injected IToaster.ShowAsync(text, cfg => {...}) (MAUI) or IToastService.ShowAsync(...) (Blazor). Supports auto-dismiss with configurable duration, manual dismiss via IDisposable, pill or fill-horizontal display modes, top/bottom positioning, queue or stack mode for multiple toasts, indeterminate spinner, countdown progress bar, icon, tap command/callback, full styling (colors, border, corner radius), feedback, screen reader announce, and iOS safe area awareness. No XAML or OverlayHost required — the overlay auto-attaches on first use (MAUI + Blazor)
Feature
Dialogs — Service-first dialog system that emulates the classic alert/confirm/prompt primitives with owned (non-native), animated, themeable dialogs on MAUI and Blazor. Inject IDialogService and await Alert (Task), Confirm (Task<bool>), or Prompt (Task<PromptResult>). Modal and queued so awaited calls show one at a time; backdrop tap cancels (Escape/Enter on Blazor); colors follow the theme tokens for automatic light/dark. Per-call configure sets the DialogAnimation (None/Fade/SlideTop/SlideBottom/SlideLeft/SlideRight/Zoom/Pop) and styling; customize globally via ConfigureDialogs (MAUI) / AddShinyDialogs(o => ...) (Blazor), or fully replace the card with a ContentTemplate (MAUI) / <DialogHost Template> (Blazor). MAUI auto-attaches via UseShinyControls(); Blazor needs AddShinyDialogs() + a single <DialogHost /> (MAUI + Blazor)
Feature
Dialogs — ActionSheet — New IDialogService.ActionSheet(title, options, cancelText, destructive?, configure?) primitive on MAUI and Blazor: an iOS-style sheet listing the supplied options with a cancel button, anchored to the bottom with a default slide-up. Returns the chosen option’s text (Task&lt;string?&gt;), or null when cancelled. Pass destructive (matching one of the options) to render that one in red. Same owned/animated/themeable/queued model as the other dialogs, and templatable via the new DialogContext.Actions/DestructiveAction/IsActionSheet + SelectCommand (MAUI) / Select(option) (Blazor) (MAUI + Blazor)
Feature
TextEntry — Material Design-inspired text entry control with animated floating placeholder that slides up on focus, customizable border styling (color, thickness, corner radius, background), left/right tool slots for icons or interactive buttons, hint text for validation errors with automatic error state coloring, character count display, password masking, read-only mode, and keyboard type selection. Includes built-in ClearButtonTool (auto-shows/hides) and speech-to-text tools in the SpeechAddins packages (MAUI uses ISpeechToTextService, Blazor uses Web Speech API). Tools are TextEntryTool subclasses on both hosts with lifecycle hooks for parent text access (MAUI + Blazor)
Feature
TextEntry Input MaskingMask property enables declarative input formatting with # as digit placeholder and auto-inserted literal characters. Supports phone numbers (###) ###-####, credit cards #### #### #### ####, dates ##/##/####, SSN, ZIP codes, and custom patterns. Text always contains raw digits for clean binding/validation; FormattedText provides the display value. Keyboard auto-sets to Numeric, cursor positioning handled on both platforms (MAUI + Blazor)
Feature
TextEntryStepperTool — Built-in TextEntryTool subclass that increments or decrements the numeric value in a TextEntry by a configurable Step amount on each tap. Auto-displays +N or -N as button text when Text is not explicitly set. Place in LeftTools (decrement) and RightTools (increment) for a numeric stepper pattern (MAUI + Blazor)
Feature
Slider — A slider control with a two-color gradient track, blended thumb border that samples the gradient at the current position, tooltip with custom templates, and full drag/tap interaction via JS interop (Blazor) or pan/tap gesture (MAUI) (MAUI + Blazor)
Feature
ProgressBar — A progress bar with gradient fill and a configurable Vista-style shimmer pulse that sweeps left-to-right across the filled portion. Supports determinate mode with Value/Minimum/Maximum, indeterminate mode with sliding animation, text overlay with configurable format, and pulse triggers on value change or timed interval. Pulse has configurable PulseLength (sheen width as fraction of fill) and PulseSpeed (ms for one sweep). Gradient mode uses GradientStartColor/GradientEndColor for a linear gradient fill (MAUI + Blazor)
Feature
Overlay & LoadingOverlay — Full-screen overlay control with configurable backdrop color, transparency, and fade animation. The base Overlay supports any custom content via DataTemplate (MAUI) or RenderFragment (Blazor). The LoadingOverlay subclass provides a built-in loading template with either an indeterminate spinner (ActivityIndicator) or a determinate progress bar (using the ProgressBar control). Bindable IsShown property for show/hide with smooth animation, plus Message text support (MAUI + Blazor)
Feature
CarouselGallery — Netflix-style horizontal carousel with snap-to-center behavior, configurable scale transforms for focused/unfocused items, peek area insets, infinite loop mode, two-way position tracking, and position changed command. Uses native platform recycler views on MAUI (Android RecyclerView with LinearSnapHelper, iOS UICollectionView with custom CarouselFlowLayout, Windows ItemsRepeater in horizontal ScrollViewer with SnapPointsType) and CSS scroll-snap with dot indicators on Blazor (MAUI + Blazor)
Feature
StaggeredGrid — Pinterest-style masonry/waterfall layout with variable-height items arranged in columns using a shortest-column-first algorithm. Configurable column count, column spacing, and row spacing. Uses native staggered layout managers on MAUI (Android StaggeredGridLayoutManager, iOS custom WaterfallLayout UICollectionViewLayout, Windows WaterfallVirtualizingLayout for ItemsRepeater) and CSS column-count with break-inside:avoid on Blazor (MAUI + Blazor)
Feature
VirtualizedGrid — Full-featured grouped grid with sticky section headers, virtualization, orientation-aware column counts (portrait/landscape), cell padding, load-more button with loading state, and item visibility tracking. Supports flat and grouped data sources with configurable group header templates. Load-more button renders as a proper footer at the end of the data across all platforms (iOS supplementary section footer, Android custom view holder, Windows MAUI-to-platform bridge). Uses native grid layouts on MAUI (Android GridLayoutManager with StickyHeaderDecoration and SpanSizeLookup, iOS UICollectionViewCompositionalLayout with pinned boundary supplementary items, Windows ItemsRepeater with UniformGridLayout) and CSS Grid with Blazor Virtualize component on Blazor (MAUI + Blazor)
Feature
CarouselGallery SnapCount — New SnapCount property (int, default 1) controls snap behavior. Set to 0 for Netflix-style free scrolling with no snapping. Works across all platforms: Android attaches/detaches LinearSnapHelper, iOS adjusts deceleration rate and targeting, Windows toggles SnapPointsType, Blazor uses CSS scroll-snap-type (MAUI + Blazor)
Feature
Feedback Service — All interactive controls fire events through the injectable IFeedbackService. The default HapticFeedbackService provides tactile click/long-press feedback. Replace it with SetCustomFeedback<T>() in UseShinyControls() to implement text-to-speech, sound effects, analytics, or any custom response. ChatView passes message text as details, enabling TTS for incoming messages. Every control’s UseFeedback property (default true) gates whether feedback fires
Feature
Barcodes & QR Codes (separate packages Shiny.Maui.Controls.Barcodes and Shiny.Blazor.Controls.Barcodes) — Pure-managed 1D and 2D barcode renderer powered by ZXing.Net, with a custom PNG encoder built on zlib + CRC32 + Adler32 (no SkiaSharp, no System.Drawing — AOT-safe on every TFM, ships clean on iOS, Android, Mac Catalyst, Windows, and Blazor WebAssembly). BarcodeView (a ContentView on MAUI, a Razor component on Blazor) renders any of 13 symbologies — QRCode, Aztec, DataMatrix, Pdf417, Code128, Code39, Code93, Codabar, Ean8, Ean13, UpcA, UpcE, Itf — with bindable Value, Format, PixelWidth, PixelHeight, MarginPixels, ForegroundColor, and BarcodeBackgroundColor. QRCodeView is a BarcodeView subclass that locks Format to QRCode, exposes a single square Size property, and adds ErrorCorrection (Low / Medium / Quartile / High — higher tolerates more damage at the cost of capacity). On Blazor, output defaults to inline SVG with shape-rendering="crispEdges" and a single horizontal-run <path> so it scales infinitely without aliasing and stays tiny in DOM size; switching ImageFormat to Png renders an <img> with a data: URI. Optional CssWidth / CssHeight decouple the encoder resolution from the host element’s CSS size. For headless rendering — PDF exports, email attachments, label printing — the static BarcodeRenderer exposes RenderPng(string, BarcodeFormat, BarcodeRenderOptions?), RenderSvg(...), and RenderDataUri(...). Invalid 1D payloads (e.g. EAN-13 with non-numeric content) silently clear the image instead of throwing. XAML namespace xmlns:bc="http://shiny.net/maui/barcodes" (MAUI + Blazor)
Feature
TreeView — Hierarchical tree control with lazy-loaded branches via async RootLoader / ChildrenLoader, configurable expand/collapse/retry icons (with sensible / / glyph fallbacks), single or multi-select via SelectionMode, per-item CanExpand / CanSelect predicates, retry-on-load-failure, optional vertical guide lines between parent and children, and drag/drop reorder with event-only mutation. RootLoader, ChildrenSelector, ChildrenLoader, and HasChildrenSelector are independent so the same control handles fully in-memory trees, half-lazy trees, and fully remote trees. Events + matching *Command bindables: ItemSelected, ItemExpanded, ItemCollapsed, LoadFailed, ItemDropped. Drag/drop reports Above / Below / Into drop positions with visual drop indicators — Blazor uses native HTML5 drag events via JS interop (required for Safari/Firefox), while MAUI uses platform drag gestures with a pan-gesture fallback on Mac Catalyst, AppKit, and GTK4. Public methods: ExpandAll, ExpandAllAsync, CollapseAll, Expand(item), Collapse(item), Refresh(item), ReloadAsync (preserves expansion/selection on Blazor), FindNode(item). Blazor adds keyboard navigation on top of the same shape (MAUI + Blazor)
Feature
BadgeView — Wraps any single content view and overlays a small notification badge at one of four corners (TopLeft, TopRight, BottomLeft, BottomRight) with per-corner OffsetX / OffsetY nudge. Bind your unread / cart / pending count to Text — an empty string auto-hides the badge so you don’t write show/hide logic. MaxCount collapses overflow to "99+" (or any chosen ceiling). IsDot switches to a simple notification dot mode with configurable DotSize for “has new” indicators. Full styling: BadgeColor, BadgeTextColor, BadgeBorderColor (creates a clean ring around the badge), BadgeBorderThickness, CornerRadius (default fully-rounded pill), BadgePadding, FontSize, and FontAttributes / FontWeight. Optional show/hide scale + fade animation (IsAnimated) and a continuous attention-grabbing pulse (IsPulsing). Blazor honors prefers-reduced-motion and disables both animations when set (MAUI + Blazor)
Feature
SkeletonView — Lightweight content placeholder for “loading” states with smooth shimmer / pulse animation, configurable corner radius, color, and animation speed. Drop in to indicate where content will land while you wait for data, without flickering layouts. Works as a standalone control or composed into row templates so each list item shows a placeholder until it loads (MAUI + Blazor)
Feature
ParallaxCollectionView (MAUI) / ParallaxList (Blazor) — Scrollable list with a hero header that translates at a configurable fraction of the scroll offset — the App Store / profile-page parallax effect. MAUI wraps a real CollectionView and drives the hero from CollectionView.Scrolled (no platform handlers), so multi-column GridItemsLayout, selection, item-selected commands, empty views, and Scrolled event arguments (ParallaxScrollEventArgs with verticalOffset, headerTranslation, headerVisibleHeight) all pass through. Blazor uses a small JS scroll listener that mutates transform / opacity directly via requestAnimationFrame, so the parallax runs at native scroll framerate without re-rendering Razor components. Configurable HeaderHeight, MinHeaderHeight, ParallaxFactor (0 = pinned, 1 = scrolls with content), CollapseToSticky (clamp to min after scrolling past), and FadeHeaderOnScroll. Drive sticky titles, fading nav chrome, or scroll-linked animations from the Scrolled event (MAUI + Blazor)
Feature

Desktop add-on (Shiny.Maui.Controls.Desktop) — A single MAUI-desktop-only package that bundles three features sharing the same TFM matrix (net10.0;-windows;-maccatalyst;-macos + Linux GTK4): a system tray / status-bar icon, Visual-Studio-style window docking, and a touch / kiosk on-screen keyboard. Blazor gets the docking + on-screen keyboard via the companion Shiny.Blazor.Controls.Kiosk package.

Tray Icon (Shiny.Maui.Controls.Desktop.TrayIcon namespace) — Cross-platform system tray / status-bar / menu-bar icon. Supports Windows (Shell_NotifyIcon via Win32 P/Invoke with a message-only window for click routing), macOS AppKit (native NSStatusItem via the net10.0-macos bindings), MacCatalyst (bridges to AppKit at runtime via the Objective-C runtime with [UnmanagedCallersOnly] trampolines for menu callbacks), and Linux (libayatana-appindicator3 + GTK 3 — depends on libayatana-appindicator3-1 and libgtk-3-0 system packages). API: ITrayIconFactory resolved from DI, ITrayIcon with SetIcon(Func<Stream>), Tooltip, Title, Badge, IsVisible, IsTemplateImage (macOS dark/light auto-tint), SetMenu(TrayMenu), ShowMenu(), ShowNotification(title, message), StartAnimation(frames, interval) / StopAnimation() / IsAnimating, and PrimaryClick/SecondaryClick/DoubleClick events. Menus are built fluently with TrayMenu.Build(b => b.Item(...).Check(...).Separator().Submenu(...)); TrayMenuItem supports per-item Icon (Func<Stream> rendered next to the label on all four platforms) and Accelerator strings parsed by TrayAccelerator and dispatched via the OS — RegisterHotKey on Windows (process-global), native KeyEquivalent + modifier mask on macOS / Catalyst (app-foreground), and gtk_widget_add_accelerator on a GtkAccelGroup on Linux (menu-focused, best-effort). Mutating any item rebuilds the native menu automatically. Badge renders as a composited red pill on the Windows HICON (System.Drawing.Common, Windows TFM only) and beside the icon on macOS / Linux. ShowNotification routes to Shell_NotifyIcon NIF_INFO on Windows, NSUserNotificationCenter on macOS / Catalyst, and libnotify on Linux (no-op when libnotify is missing). Windows auto-wraps PNG bytes in an ICO container so the same PNG asset works on every platform. Register with .UseTrayIcon() in MauiProgram.cs. (Migrating from the previous standalone Shiny.Maui.Controls.TrayIcon package: swap your <PackageReference> and change using Shiny.Maui.Controls.TrayIcon; to using Shiny.Maui.Controls.Desktop.TrayIcon; — the UseTrayIcon() extension method in the Shiny namespace is unchanged.)

On-Screen Keyboard (Shiny.Maui.Controls.Desktop.OnScreenKeyboard namespace; companion Shiny.Blazor.Controls.Kiosk.OnScreenKeyboard for Blazor) — Touch / kiosk on-screen keyboard for desktop apps and Blazor. US-QWERTY with three layers (lowercase / Shift / 123-symbols), bottom-docked, auto-shows when an Entry / Editor (MAUI) or <input> / <textarea> (Blazor) gains focus. Critically does NOT steal focus when keys are tapped — every key uses pointerdown + preventDefault() (Blazor) or Focusable = false + intercepted PointerPressed (MAUI). Press-and-hold autorepeat (400ms delay, 50ms interval, both configurable). Dispatches into the focused control via managed Text mutation at CursorPosition (MAUI) or document.execCommand('insertText', char) after focus restore (Blazor) — no native synthetic key events, so no macOS Accessibility entitlement required and Mac App Store distribution is fine. Full AutomationPeer (Windows / MAUI / GTK) and ARIA role="button" + aria-keyshortcuts (Blazor) tree so switch-input users can step through keys. Theme tokens (OnScreenKeyboardKeyBrush / --shiny-osk-key-bg etc.) mirror docking’s pattern. Public surface: IOnScreenKeyboard (MAUI) / IOnScreenKeyboardService (Blazor) with Show() / Hide() / Toggle() / IsVisible / VisibilityChanged, and an OnScreenKeyboardOptions for auto-show-on-focus, push-content vs overlay, height, theme, and autorepeat timing. Register with .UseOnScreenKeyboard(opts => ...) on MAUI or services.AddShinyOnScreenKeyboard(opts => ...) on Blazor. Limitations: MAUI inputs / DOM inputs only (no system-wide injection), no Shadow DOM, no IME / dead-key composition, US-QWERTY layout only.

Docking (Shiny.Maui.Controls.Desktop.Docking namespace; companion Shiny.Blazor.Controls.Kiosk for Blazor (kiosk-shaped add-on, namespace Shiny.Blazor.Controls.Kiosk.Docking, also home to the on-screen keyboard)) — Visual-Studio-style window docking for desktop apps. Dockable tool windows, tabbed groups, draggable splitters, auto-hide rails, and tear-off floating windows. DockHostView (MAUI) / <DockHost /> (Blazor) attaches inside any existing page — not a ContentPage subclass, so consumers keep their Shell architecture. Public surface: layout schema POCOs (DockRoot, DockWindowState, DockSplit, DockGroup, DockEmpty, DockTab) with [JsonPolymorphic] + a source-generated JsonSerializerContext for AOT-safe JSON round-trip via DockSerialization.Serialize/Deserialize; contracts IDockHost (per-window controller with LoadAsync / Snapshot / ShowPanelAsync / HidePanelAsync / ActivatePanelAsync / ResetLayoutAsync / SetRailCollapsedAsync / IsLocked / Events — implemented directly by DockHostView and <DockHost>), IDockableContent (optional interface on panel views for per-instance Title / Icon, CanClose / CanFloat, activation callbacks, and pointer-down claim for embedded editors), IDockableContentFactory (async Task<View> CreateAsync(string instanceId, ...) for MAUI / Task<RenderFragment> for Blazor, plus DisplayName / Icon — registered via .AddDockPanel<TView>("panel-id", displayName: …, icon: …)), IDockLayoutStore (bring-your-own — no default ships; attach via the host’s LayoutStore property for auto-load at startup and debounced auto-save on every layout change), IDockLayoutMigrator (forward-only schema migrations), IDockEvents (LayoutChanged / PanelActivated / DragStarted / DragCompleted / DragCancelled), and IDockCommandScope (scopes Ctrl+W close-tab, Ctrl+Tab MRU, Ctrl+Alt+PgUp/Dn group nav to the dock surface). Fully interactive on both hosts: drag tabs to merge (drop center), split (drop edge), reorder (drop in the tab strip), or tear off floating windows (drop outside the host — movable, resizable, re-dockable, with persisted bounds); drag splitters with persisted clamped ratios; collapse individual panels to slim edge bars that restore on click (whole rails via SetRailCollapsedAsync); lock the layout read-only with IsLocked. Schema versioning (SchemaVersion + MinReadableVersion) is wired in from day one, and unknown PanelTypeIds land in a missing-panels tray rather than silently dropping. Register with .UseShinyDocking() + .AddDockPanel<TView>("id") on MAUI, services.AddShinyDocking().AddDockPanel<TComponent>("id") on Blazor; host controls accept InitialLayout, LayoutStore, and IsLocked. Cross-window drag uses mouse-down implicit capture — no global mouse hooks, no macOS Accessibility entitlement required.

Feature
ShinyToolbar & ShinyTabBar (Blazor only) — Two screen-docked navigation chromes. ShinyToolbar docks to the Top or Bottom of its scroll container as an action bar with a Title, icon Items (links or buttons with Badge/IconColor), and StartContent/ChildContent/EndContent slots; position: sticky reserves its height while page content scrolls under it. ShinyTabBar is a mobile-style bottom tab bar (position: fixed) with two-way @bind-SelectedKey, optional filled ActiveIcon for the selected state, and Badges ("" renders a dot). Both support a Frosted glass toggle via CSS backdrop-filter. On MAUI, use Shell tab bars / ToolbarItems or FloatingPanel instead (Blazor)
Feature
ShinyToolbar overflow menu — Trailing toolbar Items that don’t fit the available width automatically collapse into a hamburger dropdown behind an overflow (“more”) button, popping back out as the bar widens (OverflowEnabled, default true). A bundled toolbar.js ResizeObserver measures each item’s intrinsic width and reports how many fit (reserving room for the overflow button at the boundary); menu entries mirror each item’s icon, Text, and Badge, raise the same ItemClicked, and close on outside click or selection. Customize via OverflowIcon, OverflowText, OverflowAriaLabel, MenuBackgroundColor, and MenuTextColor. Overflow is auto-disabled when EndContent is supplied (Blazor)
Feature
CameraView (separate packages Shiny.Maui.Controls.Camera / Shiny.Blazor.Controls.Camera) — Cross-platform camera preview on iOS, Android, Windows, macOS AppKit, and Blazor WASM with zoom, torch, lens/device selection, photo + video capture, and live color filters (Mono/Noir/Sepia/Vivid/Cool/Warm/Fade/Chrome/Instant/Tonal). Filters apply to the live preview and captured photos (Apple + Android; recorded video records the raw feed; Windows has no live filter). A pluggable IFrameAnalyzer pipeline streams frames off the UI thread with per-analyzer drop-on-busy back-pressure; each analyzer raises its own strongly-typed event (or bindable Command), can be declared right in XAML, and draws styled OverlayBoxes via the built-in CameraOverlayView. Analyzers can be added/removed live, or toggled on/off in place via FrameAnalyzer.IsEnabled (bindings + state preserved), with ShowBoundingBox to suppress just the boxes. Modular add-ons Shiny.Maui.Controls.Camera.Barcode/.Face/.Motion/.Ocr/.Documents scan barcodes, detect faces and motion, run OCR, and extract structured documents (Invoice with order lines, Receipt with line items + per-tax breakdown + totals, AAMVA DriversLicense, HealthCard, CreditCard via IIN+Luhn, Passport via MRZ) — each a strong record with nullable fields + a typed event. Register with .UseShinyCamera() (MAUI + Blazor)
Enhancement
CameraView — single analyzer, array events & scan window — The frame-analysis pipeline now runs one analyzer at a time: CameraView.Analyzers (collection) is replaced by a single bindable CameraView.Analyzer (the content property), assigned or swapped live and cleared with null. Detection events now always deliver an array since a frame can hold several detections — BarcodeAnalyzer.BarcodeDetected (singular BarcodeDetectedEventArgs) becomes BarcodesDetected (BarcodesDetectedEventArgs.Barcodes, with .First for the common single-code case); faces and motion regions were already arrays. New FrameAnalyzer.ScanWindow (a normalized RectF?) restricts barcode scanning to a region — natively: Apple Vision’s regionOfInterest (iOS/macOS) and a Y-plane crop fed to MLKit (Android), so the engine only decodes that band. This both prevents picking up other codes in one shot and speeds up scanning, and the built-in overlay dims everything outside it and frames a viewfinder reticle (tunable via CameraOverlayView.ScanWindowColor / ScanWindowScrimColor). Blazor gains matching shape: a typed Analyzer parameter (BarcodeAnalyzer, incl. ScanWindow) replaces the EnableBarcode flag, and BarcodesDetected replaces BarcodeDetected. Breaking: CameraView.AnalyzersAnalyzer; BarcodeDetected/BarcodeDetectedCommand/BarcodeDetectedEventArgsBarcodesDetected/BarcodesDetectedCommand/BarcodesDetectedEventArgs; Blazor EnableBarcode/BarcodeDetectedAnalyzer/BarcodesDetected (MAUI + Blazor)
Enhancement
MotionAnalyzer — localized regions — Motion is clustered into separate regions, so movement in two spots produces two boxes instead of one box spanning both. MotionEventArgs now carries Regions (one normalized RectF per moving area) alongside Region (their union) and Intensity; tune granularity with GridColumns / CellThreshold (MAUI)
Fix
TextPickerCell value binding — A SelectedItem set from code or a binding now reflects in the cell’s value label and the underlying picker selection (previously only the user tapping the picker updated the display), and it re-syncs when ItemsSource is populated asynchronously (MAUI)
Enhancement
FloatingPanel IsContentScrollEnabled — New property (default true) that wraps panel content in a ScrollView. Set it false when the content already scrolls itself (a TableView/CollectionView) — nesting scroll-views collapses the inner one to near-zero height, leaving its rows blank (MAUI)
Fix
CameraView live filter (Android & Apple) — Color filters now apply to the live preview. On Android the PreviewView renders in Compatible (TextureView) mode so the RenderEffect colour matrix actually affects the camera pixels — previously it defaulted to a SurfaceView, whose separate compositor surface ignored the effect, so filters did nothing to the preview (live preview filtering requires API 31+; captured photos are filtered on all versions). On iOS/Mac Catalyst applying a filter no longer blanks/“stops” the preview: the handler previously hid the AVCaptureVideoPreviewLayer, but that layer is the view’s backing layer, so hiding it also hid the filtered-frame overlay subview — the opaque overlay now simply covers the live preview instead (MAUI)
Fix
SignaturePad export clipping — The exported PNG no longer cuts off the bottom of the signature. Strokes are captured in the on-screen canvas coordinate space (typically taller than the default 600×200 export), and were previously drawn into the export bitmap at raw coordinates, clipping anything below the export height — most visible on Android, where the panel canvas is tallest. They are now scaled uniformly to fit and centered within ExportWidth×ExportHeight, preserving the whole signature and its aspect ratio (MAUI)
Fix
CameraView filter preview (Apple) — Selecting a color filter no longer blanks the iOS / Mac Catalyst preview. The filtered-frame overlay is now pinned to the preview with layout constraints instead of an autoresizing mask seeded from a zero frame, which could leave it 0×0 so filtered frames rendered into nothing (MAUI)
Feature
Blazor CameraView lens selection — New CameraId parameter and GetAvailableCamerasAsync() method (returning CameraDevice Name) let you enumerate and pin a specific video input device — useful on machines with several webcams. Device labels populate once permission is granted (Blazor)
Enhancement
Blazor CameraView live options — Changing Facing, CameraId, EnableBarcode, or ShowOverlay while running now re-acquires the stream automatically (matching MAUI’s live toggling), and CapturePhotoAsync() bakes the current Filter into the captured still so it matches the preview (Blazor)
Feature
CameraView Canadian health cards & licencesHealthCardAnalyzer now detects the issuing Canadian province from on-card text and applies that province’s member-number format — Quebec/RAMQ (4 letters + 8 digits), Ontario/OHIP (10 digits + 2-letter version code), BC Personal Health Number, Alberta/AHCIP, and the rest — surfacing a new HealthCard.Province plus a Plan field (unknown layouts fall back to the generic digit-run heuristic). DriversLicenseAnalyzer adds DriversLicense.Jurisdiction (the AAMVA DAJ province/state) and now infers Canadian CCYYMMDD date order from the province code when the country element is absent, and accepts the legacy AAMVA file header in addition to ANSI. Note: Ontario & Quebec driver’s licences carry no PDF417 barcode and still cannot be scanned via AAMVA (MAUI)
Feature
CameraView ReceiptAnalyzer — New document analyzer in Shiny.Maui.Controls.Camera.Documents that extracts a point-of-sale receipt into a strongly-typed Receipt record: merchant name + phone, receipt/invoice number, date and time, purchased line items (Receipt.Lines), a per-tax breakdown (Receipt.Taxes, each with an optional rate), plus Subtotal, total Tax, Tip, Discount, Total, and best-effort Currency / PaymentMethod / CardLast4. OCR + best-effort rules; supply a custom IDocumentParser<Receipt> for production accuracy. The sample’s Camera page now exercises every document analyzer (Invoice, Receipt, Health Card, Driver’s License, Credit Card, Passport) (MAUI)
Enhancement
CameraView document analyzers — frame accumulation — Document analyzers now merge a document’s fields across a few frames and raise DocumentDetected once with the richest combined record, instead of firing on every frame with a stream of partial/incomplete objects as the document slides into focus. Tune with AccumulationFrames (default 5; set 1 for the old per-frame behavior) and ResetAfterEmptyFrames (re-arm once the document leaves view); the analyzer also fires early when the parse is complete. Custom parsers opt in via two new (defaulted, non-breaking) IDocumentParser<T> methods, Merge and IsComplete (MAUI)
Enhancement
MotionAnalyzer — debounced eventMotionChanged is now debounced so it isn’t twitchy: motion is reported started only after EnterFrames consecutive frames above threshold (default 3) and stopped only after ExitFrames below it (default 5). The overlay boxes remain un-debounced so they stay responsive (MAUI)
Feature
CameraView gated “scan trigger” — Frame analyzers no longer push a result on every frame. Each analyzer still draws its bounding boxes continuously, but a result is delivered only while it’s armed — call CameraView.Scan() (or bind a button/Fab to ScanCommand) to arm every enabled analyzer for one scan. The next confirmed detection fires once (single-shot), then the analyzer goes quiet; a per-analyzer OnDetected (Func<TArgs, Task<bool>>, can be async) decides continuation — return true to keep scanning, false to stop. The typed event/Command still fire but only while armed (and a value lingering in view is de-duplicated). For “scan then freeze”, call CaptureAndStopAsync() inside OnDetected. Blazor mirrors this imperatively: await camera.RequestBarcodeAsync(ct) arms, resolves on the next decode, then goes quiet (loop to keep scanning); BarcodeDetected is now gated to outstanding requests. Breaking: FrameAnalyzer.CaptureOnDetection / StopOnDetection and CameraView.DetectionCaptured are removed — replace with OnDetected + CaptureAndStopAsync() (MAUI + Blazor)
Enhancement
CameraView barcode scanning goes nativeBarcodeAnalyzer and the driver’s-license PDF417 read in DriversLicenseAnalyzer now use the platform’s built-in scanner — Apple Vision (VNDetectBarcodesRequest) on iOS / Mac Catalyst / macOS and Android MLKit (BarcodeScanning) — instead of decoding ZXing.Net over the luminance plane. This brings the same on-device ML detection the OS uses elsewhere: faster, far better at angled / partially-obscured / low-contrast codes, and it reads several codes in one frame (delivered through the gated scan trigger — see above). BarcodeAnalyzer.Formats filters the symbologies natively (Vision Symbologies / MLKit SetBarcodeFormats) and is settable inline in XAML as a comma-separated list — Formats="QrCode,Ean13,Code128". Breaking: BarcodeDetectedEventArgs.Format is now Shiny.Controls.Camera.BarcodeFormat (was the ZXing enum), and barcode scanning is a no-op on Windows and bare net10.0 (no native scanner). Barcode rendering (Shiny.Maui.Controls.Barcodes / Shiny.Blazor.Controls.Barcodes) is unaffected and still uses the pure-managed ZXing encoder (MAUI)
Enhancement
CameraView OCR shared once per frame — The OCR-backed analyzers (OcrAnalyzer and every document analyzer — Invoice/Receipt/HealthCard/CreditCard/Passport) now share a single OCR pass per frame instead of each running their own. The shared TextRecognizer caches its result on the frame instance, so enabling five document analyzers at once does one recognition per frame, not five — a large speed-up when multiple are active. The shared pass also runs with Vision language correction off, which improves accuracy on structured fields (license/MRZ/card numbers, totals, dates) that the dictionary correction was corrupting by snapping codes to words; parsers fuzzy-match the raw text (MAUI)
Feature
CameraView document deskew before OCR — The document analyzers (Invoice/Receipt/HealthCard/CreditCard/Passport) now detect the document, perspective-correct (deskew) it, and OCR the flattened crop — the single biggest accuracy lever for real-world capture, since keystoned text from an angled card/ID reads poorly. It runs inside the live analyzer pipeline, so the CameraView preview is untouched (this is not the modal document-scanner UI), shares the one-OCR-pass-per-frame cache, and turns the overlay into the detected document outline (DocumentAnalyzer.BoxColor). Per platform: iOS/Mac Catalyst/macOS uses Vision (VNDetectDocumentSegmentationRequest) + Core Image; Windows uses OpenCvSharp (runtime.win, Windows TFM only); Android uses a dependency-free managed detector + a native Matrix.setPolyToPoly warp (no OpenCV, keeping the package trim/AOT-clean). All platforms fall back to whole-frame OCR when no document is found; bare net10.0 is a no-op (MAUI)
Fix iOS
CameraView close-range focus (Apple) — The iOS / Mac Catalyst camera now stays sharp when you move in close (e.g. to scan a document or card). The capture device was never put into a focus mode, so it could sit one-shot/locked and never re-focus at near range. The handler now configures continuous autofocus, clears any near-limit AutoFocusRangeRestriction so the lens can reach macro range, centers the focus point of interest, enables smooth autofocus, and pairs continuous auto-exposure — applied on session start and on every camera switch (MAUI)
Feature
Carousel (Blazor) — A new Embla-style Carousel<TItem> built on a transform-based drag engine: click-and-drag on desktop and flick-with-momentum on touch, replacing native scroll-snap. Adds Align (Start/Center/End), SlidesPerView, SlidesToScroll, VariableWidths, vertical orientation (ViewportHeight), Rtl, seamless Loop (per-slide repetition, works with variable widths), DragFree momentum, scroll-linked Effect (Scale/Opacity/Parallax/Fade) that animates live while dragging, discrete AutoPlay with a scroll-position progress bar plus continuous AutoScroll marquee, and chrome for a counter, dot indicators (one per snap), and a thumbnail strip. Methods NextAsync/PreviousAsync/GoToAsync/GoToSlideAsync, two-way CurrentPosition, keyboard navigation, and lazy item loading. Use CarouselGallery for MAUI/Blazor parity; use Carousel for the richer Blazor-only drag experience (Blazor)