HoverMenuExtender¶
The HoverMenuExtender displays a popup panel when the user hovers over a target control. It supports configurable show/hide delays, positional placement, and hover CSS styling. The popup remains visible while the mouse is over either the target or the popup itself.
Original Ajax Control Toolkit documentation: https://www.asp.net/ajax/ajaxcontroltoolkit/HoverMenuExtender
Features Supported in Blazor¶
TargetControlID— ID of the control that triggers the hover menuPopupControlID— ID of the panel element to display as a hover menuPopupPosition— Position of the popup relative to the targetOffsetX— Horizontal offset in pixels from the calculated positionOffsetY— Vertical offset in pixels from the calculated positionPopDelay— Delay in milliseconds before showing the popupHoverDelay— Delay in milliseconds before hiding the popupHoverCssClass— CSS class applied to the target while the hover menu is visibleEnabled— Enable or disable the extender behaviorBehaviorID— Optional identifier for JavaScript behavior lookup
PopupPosition Enum¶
enum PopupPosition
{
Left = 0, // To the left of target
Right = 1, // To the right of target (default for HoverMenuExtender)
Top = 2, // Above target
Bottom = 3, // Below target
Center = 4 // Centered on target
}
Web Forms Syntax¶
<asp:Panel ID="pnlRow" runat="server" CssClass="data-row">
<span>Row content here</span>
</asp:Panel>
<asp:Panel ID="pnlActions" runat="server" style="display: none;" CssClass="hover-actions">
<asp:Button ID="btnEdit" Text="Edit" runat="server" />
<asp:Button ID="btnDelete" Text="Delete" runat="server" />
</asp:Panel>
<ajaxToolkit:HoverMenuExtender
ID="hme1"
runat="server"
TargetControlID="pnlRow"
PopupControlID="pnlActions"
PopupPosition="Right"
HoverDelay="200"
PopDelay="100"
HoverCssClass="row-hover"
OffsetX="5" />
Blazor Migration¶
<div ID="pnlRow" class="data-row">
<span>Row content here</span>
</div>
<div ID="pnlActions" style="display: none;" class="hover-actions">
<Button ID="btnEdit" Text="Edit" />
<Button ID="btnDelete" Text="Delete" />
</div>
<HoverMenuExtender
TargetControlID="pnlRow"
PopupControlID="pnlActions"
PopupPosition="PopupPosition.Right"
HoverDelay="200"
PopDelay="100"
HoverCssClass="row-hover"
OffsetX="5" />
Migration is simple: Remove the ajaxToolkit: prefix and runat="server". Use full enum type name for PopupPosition. Everything else stays the same!
Properties Reference¶
| Property | Type | Default | Description |
|---|---|---|---|
TargetControlID |
string |
(required) | ID of the control that triggers the hover menu |
PopupControlID |
string |
"" |
ID of the panel element to display as a hover menu |
PopupPosition |
PopupPosition |
Right |
Position of the popup relative to the target: Left, Right, Top, Bottom, Center |
OffsetX |
int |
0 |
Horizontal offset in pixels from the calculated position |
OffsetY |
int |
0 |
Vertical offset in pixels from the calculated position |
PopDelay |
int |
0 |
Delay in milliseconds before showing the popup after mouse enters the target |
HoverDelay |
int |
300 |
Delay in milliseconds before hiding the popup after mouse leaves the target and popup |
HoverCssClass |
string |
"" |
CSS class applied to the target control while the hover menu is visible |
BehaviorID |
string |
TargetControlID | Optional identifier for JavaScript behavior lookup |
Enabled |
bool |
true |
Whether the extender is active |
Usage Examples¶
Basic Hover Menu¶
@rendermode InteractiveServer
<div ID="targetItem" style="padding: 10px; border: 1px solid #ddd; cursor: pointer;">
Hover over me to see actions
</div>
<div ID="hoverPanel" style="display: none; background: white; border: 1px solid #ccc; padding: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.15);">
<button>Edit</button>
<button>Delete</button>
<button>Share</button>
</div>
<HoverMenuExtender
TargetControlID="targetItem"
PopupControlID="hoverPanel"
PopupPosition="PopupPosition.Right"
HoverDelay="200" />
Row Actions on Hover¶
@rendermode InteractiveServer
@foreach (var item in items)
{
<div ID="@($"row-{item.Id}")" class="list-row">
<span>@item.Name</span>
</div>
<div ID="@($"actions-{item.Id}")" style="display: none;" class="action-panel">
<button onclick="@(() => Edit(item.Id))">✏️ Edit</button>
<button onclick="@(() => Delete(item.Id))">🗑️ Delete</button>
</div>
<HoverMenuExtender
TargetControlID="@($"row-{item.Id}")"
PopupControlID="@($"actions-{item.Id}")"
PopupPosition="PopupPosition.Right"
HoverDelay="300"
HoverCssClass="row-highlighted"
OffsetX="10" />
}
<style>
.list-row { padding: 10px; border-bottom: 1px solid #eee; }
.row-highlighted { background: #f0f8ff; }
.action-panel { background: white; border: 1px solid #ddd; padding: 8px; border-radius: 4px; }
</style>
@code {
private List<Item> items = new();
void Edit(int id) { /* Edit logic */ }
void Delete(int id) { /* Delete logic */ }
}
Tooltip-Style Hover Menu¶
@rendermode InteractiveServer
<span ID="helpIcon" style="cursor: help; font-size: 1.2em;">ℹ️</span>
<div ID="helpTooltip" style="display: none; background: #333; color: white; padding: 12px; border-radius: 6px; max-width: 250px; font-size: 0.9em;">
<p>This field accepts values between 1 and 100. Leave blank for the default value.</p>
</div>
<HoverMenuExtender
TargetControlID="helpIcon"
PopupControlID="helpTooltip"
PopupPosition="PopupPosition.Bottom"
PopDelay="200"
HoverDelay="500"
OffsetY="5" />
Hover Menu with Show Delay¶
@rendermode InteractiveServer
<div ID="menuTrigger" style="padding: 8px 16px; background: #007bff; color: white; display: inline-block; border-radius: 4px;">
More Options ▼
</div>
<div ID="menuPopup" style="display: none; background: white; border: 1px solid #ddd; min-width: 150px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
<div style="padding: 8px 16px; cursor: pointer;">Option 1</div>
<div style="padding: 8px 16px; cursor: pointer;">Option 2</div>
<div style="padding: 8px 16px; cursor: pointer;">Option 3</div>
</div>
<HoverMenuExtender
TargetControlID="menuTrigger"
PopupControlID="menuPopup"
PopupPosition="PopupPosition.Bottom"
PopDelay="100"
HoverDelay="400" />
HTML Output¶
The HoverMenuExtender produces no HTML itself — it attaches JavaScript behavior to show/hide the popup panel on mouse enter/leave events.
JavaScript Interop¶
The HoverMenuExtender loads hover-menu-extender.js as an ES module. JavaScript handles:
- Monitoring mouse enter/leave events on the target and popup elements
- Applying show/hide delays (
PopDelayandHoverDelay) - Positioning the popup relative to the target with offsets
- Adding/removing the
HoverCssClasson the target element - Keeping the popup visible when the mouse moves between target and popup
Render Mode Requirements¶
The HoverMenuExtender requires InteractiveServer render mode:
Graceful Degradation¶
- SSR/Static mode: The extender silently skips initialization. The popup panel remains hidden.
- JavaScript disabled: Same as SSR — target control functions normally without hover behavior.
Migration Notes¶
From Web Forms Ajax Toolkit¶
-
Remove
ajaxToolkit:prefix -
Remove
runat="server"andIDattributes -
Use full enum type name for PopupPosition
Before (Web Forms)¶
<asp:Panel ID="pnlTarget" runat="server">
<span>Hover me</span>
</asp:Panel>
<asp:Panel ID="pnlMenu" runat="server" style="display: none;">
<a href="#">Edit</a> | <a href="#">Delete</a>
</asp:Panel>
<ajaxToolkit:HoverMenuExtender
ID="hme1"
TargetControlID="pnlTarget"
PopupControlID="pnlMenu"
PopupPosition="Right"
HoverDelay="200"
runat="server" />
After (Blazor)¶
<div ID="pnlTarget">
<span>Hover me</span>
</div>
<div ID="pnlMenu" style="display: none;">
<a href="#">Edit</a> | <a href="#">Delete</a>
</div>
<HoverMenuExtender
TargetControlID="pnlTarget"
PopupControlID="pnlMenu"
PopupPosition="PopupPosition.Right"
HoverDelay="200" />
Best Practices¶
- Set appropriate delays —
PopDelayof 100–200ms prevents accidental triggers;HoverDelayof 200–500ms gives users time to reach the popup - Hide the popup initially — Set
style="display: none;"on the popup element - Use HoverCssClass — Highlight the target to show the hover menu is active
- Position wisely — Use
RightorBottomfor most use cases; adjust with offsets - Keep popup content interactive — Users should be able to interact with buttons/links in the popup
Troubleshooting¶
| Issue | Solution |
|---|---|
| Popup not appearing | Verify TargetControlID and PopupControlID match their elements' IDs. Ensure @rendermode InteractiveServer is set. |
| Popup disappears too quickly | Increase HoverDelay to give users more time (300–500ms). |
| Popup appears too slowly | Decrease PopDelay (0–100ms). |
| Popup positioned incorrectly | Try a different PopupPosition value or adjust OffsetX/OffsetY. |
| HoverCssClass not applied | Verify the CSS class name is correct and the styles are defined. |
See Also¶
- Ajax Control Toolkit Overview — How extenders work and render mode requirements
- PopupControlExtender — Click-triggered popup
- ModalPopupExtender — Full modal popup with overlay
- Original Ajax Control Toolkit: https://www.asp.net/ajax/ajaxcontroltoolkit