Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

Tooltip

Tooltip is a themed bubble that points at a target. It either wraps the thing it describes or points at something else, and it is drawn above the page rather than in the tree — so it is never clipped by the scroll view, card or grid cell its target lives in.

  • NuGet downloads for Shiny.Maui.Controls
  • NuGet downloads for Shiny.Blazor.Controls
Frameworks
.NET MAUI
Blazor

MAUI (iOS)

Wrapping a control Placement Bound to a view-model Styled
A tooltip above the control it wraps Bottom placement, tail pointing up at the button A tooltip opened from IsOpen on the view-model Title, custom background and foreground colours

Blazor

Wrapping a control Placement Never clipped
A tooltip above the button it wraps on Blazor Bottom placement on Blazor A tooltip escaping an overflow:hidden container via the top layer
  • Two shapes — wrap the control, or point at one by reference (MAUI) or CSS selector (Blazor)
  • Auto-flipping placement — a side with no room flips to its opposite, then to the roomiest of the four
  • A tail that keeps pointing — it slides along the bubble’s edge after clamping, so it still aims at the target the bubble was moved away from
  • Never clipped — a page-level layer on MAUI, the browser’s top layer on Blazor
  • Triggers — manual, tap/click, long-press, hover, focus
  • Follows its target — re-places while open when the page scrolls or resizes
  • Themed — takes the theme’s inverse surface by default, and follows a live theme swap
  • Templated contentContentTemplate (MAUI) or BubbleContent (Blazor) instead of title and text
  • An attached shorthand on MAUI for places an element does not fit
xmlns:shiny="http://shiny.net/maui/controls"
<!-- 1. Wrapping: it finds its own target, and the wrapper does not disturb the layout. -->
<shiny:Tooltip Text="Saves without closing" Placement="Top" Trigger="LongPress">
<Button Text="Apply" />
</shiny:Tooltip>
<!-- 2. Anchored and bound: it does not have to sit near its target in the markup. -->
<shiny:Tooltip Target="{x:Reference SaveButton}"
Title="Why is this disabled?"
Text="Make a change first. Tap this hint to dismiss it."
Placement="Bottom"
ShowTail="True"
IsOpen="{Binding ShowSaveHint}"
Command="{Binding DismissHint}" />

For a one-liner where an element does not fit — inside a DataTemplate or a cell, where {x:Reference} cannot see out anyway:

<Button Text="Sync"
shiny:TooltipProperties.Text="Pushes local changes to the server"
shiny:TooltipProperties.Placement="Right"
shiny:TooltipProperties.Trigger="LongPress" />

It builds a real Tooltip behind the scenes and drives it from the target’s own lifecycle. Reach for the element form when you need binding, templated content or a command.

@* 1. Wrapping. The wrapper is display:contents, so layout is untouched. *@
<Tooltip Text="Saves without closing" Placement="TooltipPlacement.Top">
<ShinyButton Text="Apply" />
</Tooltip>
@* 2. Anchored by selector, bound. *@
<Tooltip Target="#save"
Title="Why is this disabled?"
Text="Make a change first."
Placement="TooltipPlacement.Bottom"
Trigger="TooltipTrigger.Manual"
@bind-IsOpen="showHint"
Clicked="OnHintClickedAsync" />

Differences from MAUI:

  • Target is a CSS selector string, resolved each time the bubble opens.
  • Trigger adds HoverOrFocus, which is the default and the accessible one — a hover-only tooltip is unreachable by keyboard. Tap is Click; LongPress is the touch equivalent of hover.
  • Clicked replaces Command; DismissOnClick replaces DismissOnTap.
  • MaxWidth, BubbleColor and TextColor are CSS strings.
  • Methods are async: ShowAsync(), HideAsync(), ToggleAsync().
  • There is no DismissOnTapOutside: the bubble is in the top layer and never blocks the page.

Four rules, applied in order. Auto prefers below, then above, then right, then left.

  1. A side with no room flips to its opposite.
  2. If neither fits, the roomiest side wins.
  3. The bubble is clamped to stay inside ScreenMargin.
  4. The tail slides along the bubble’s edge to keep pointing at the target, pulled in from the corners so it always meets a straight edge rather than detaching on a curve.

So Placement="Left" on a control hard against the left edge gives a bubble on the right. That is deliberate — a tooltip you cannot read is worse than one on the other side.

On MAUI this is TooltipPlacementSolver, which is public and pure: rects in, rects out. On Blazor the same rules run in the tooltip module, because placement needs the bubble’s rendered size and measuring that from .NET would mean a round trip per candidate side.

The bubble is never drawn where the tooltip is declared.

  • MAUI — it goes into a layer above the page’s content, shared with the walkthrough and dialogs, so a target inside a ScrollView, a Border or a grid cell gets a bubble that escapes all of them.
  • Blazor — it goes into the browser’s top layer via the popover API, which escapes both overflow: hidden ancestors and every z-index argument on the page. Browsers without the API fall back to fixed positioning, which still works but can be trapped by a transformed ancestor’s containing block.
Property Default Notes
Text / Title null Body, and an optional bold heading
ContentTemplate (MAUI) / BubbleContent (Blazor) null Replaces the title/text pair
Target null {x:Reference} on MAUI, a CSS selector on Blazor. Defaults to the wrapped content
TargetName null MAUI only — x:Name through the name scope
IsOpen false Two-way. Not IsVisible
Trigger Manual (MAUI) / HoverOrFocus (Blazor) On MAUI, Tap anchors through Clicked for a Button / ImageButton
Placement Auto Top / Bottom / Left / Right / Center
ShowTail / TailSize true / 7 Always off for Center
ShowDelay 0 (MAUI) / 120 (Blazor) ms a trigger must persist
AutoDismissDelay 0 ms before it closes itself
LongPressDelay 450
DismissOnTap / DismissOnClick true
DismissOnTapOutside true MAUI only. Ignored for hover and focus
Offset / ScreenMargin 8 / 12 Gap to the target; clearance from the edges
MaxBubbleWidth / MaxWidth 280 / 280px
BubbleColor / TextColor / BorderColor null Unset follows the theme
CornerRadius unset Negative follows the theme’s corner token (MAUI)
Animation / AnimationDuration Scale / 160 None / Fade / Scale / Slide
Command (MAUI) / Clicked (Blazor) null Runs when the bubble is tapped, before dismissal

Methods: Show / Hide / Toggle (async on Blazor). Events: Opened, Closed, and Tapped on MAUI.

  • MAUI’s Hover trigger needs a pointer, so it is a no-op on phones. Use LongPress there, and Focus for keyboard reachability.
  • A tooltip on a control inside a scroll view follows it while open.
  • DismissOnTapOutside (MAUI) puts a transparent catcher over the page while the bubble is up, so that tap does not also reach what is underneath. That is what you want from a popover and not from a hover hint, which is why it is ignored for the Hover and Focus triggers.
  • Walkthrough — a guided tour built on this bubble
  • Dialogs — when the message needs an answer rather than a glance