Skip to content

Conversation

@vnbaaij
Copy link
Collaborator

@vnbaaij vnbaaij commented Feb 2, 2026

  1. Cleanup Logic: Updated the stop function in init to explicitly abort and remove the resizeController for the grid instance.
  2. Dynamic AbortSignal: Updated enableColumnResizing to:
    • Detect if a grid already has a resizeController and abort it before creating a new one (e.g., when columns are re-evaluated).
  3. Create a localController if no external signal is provided from Blazor.
  4. Use an effectiveSignal for all resizing event listeners.
  5. Registry Persistence: Modified the grid registration logic to store the resizeController so it can be managed during re-initialization or disposal.
  6. Improve key handling
  7. Port v5 script improvement

These changes ensure that whenever column resizing is re-enabled (which happens in Blazor when columns change), the old JS listeners are properly cleaned up via the AbortController. It also now close any popups correctly by using ESC key

…rt and remove the resizeController for the grid instance.

2. Dynamic AbortSignal: Updated enableColumnResizing to:
• Detect if a grid already has a resizeController and abort it before creating a new one (e.g., when columns are re-evaluated).
1. Create a localController if no external signal is provided from Blazor.
2. Use an effectiveSignal for all resizing event listeners.
3. Registry Persistence: Modified the grid registration logic to store the resizeController so it can be managed during re-initialization or disposal.

These changes ensure that whenever column resizing is re-enabled (which happens in Blazor when columns change), the old JS listeners are properly cleaned up via the AbortController.
- Port v5 script improvement
@vnbaaij vnbaaij added this to the v4.14.0 milestone Feb 2, 2026
@vnbaaij vnbaaij requested a review from dvoituron as a code owner February 2, 2026 10:55
Copilot AI review requested due to automatic review settings February 2, 2026 10:55
@github-actions
Copy link

github-actions bot commented Feb 2, 2026

✅ All tests passed successfully

Details on your Workflow / Core Tests page.

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Summary - Unit Tests Code Coverage

Summary
Generated on: 2/2/2026 - 10:58:16 AM
Coverage date: 2/2/2026 - 10:58:07 AM
Parser: Cobertura
Assemblies: 1
Classes: 257
Files: 367
Line coverage: 60.9% (6256 of 10259)
Covered lines: 6256
Uncovered lines: 4003
Coverable lines: 10259
Total lines: 34545
Branch coverage: 53% (3165 of 5963)
Covered branches: 3165
Total branches: 5963
Method coverage: Feature is only available for sponsors
Tag: 5186_21587300510

Coverage

Microsoft.FluentUI.AspNetCore.Components - 60.9%
Name Line Branch
Microsoft.FluentUI.AspNetCore.Components 60.9% 53%
Microsoft.FluentUI.AspNetCore.Components.AccordionChangeEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.ActionButton`1 50%
Microsoft.FluentUI.AspNetCore.Components.ActionLink`1 0%
Microsoft.FluentUI.AspNetCore.Components.CalendarExtended 95% 86.6%
Microsoft.FluentUI.AspNetCore.Components.CalendarTitles 87% 76.6%
Microsoft.FluentUI.AspNetCore.Components.CheckboxChangeEventArgs 50%
Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1 26.2% 20.8%
Microsoft.FluentUI.AspNetCore.Components.ColumnKeyGridSort`1 0% 0%
Microsoft.FluentUI.AspNetCore.Components.ColumnOptionsLabels 100%
Microsoft.FluentUI.AspNetCore.Components.ColumnResizeLabels 100%
Microsoft.FluentUI.AspNetCore.Components.ColumnResizeOptions`1 0% 0%
Microsoft.FluentUI.AspNetCore.Components.ColumnSortLabels 100%
Microsoft.FluentUI.AspNetCore.Components.CommunicationToast 0% 0%
Microsoft.FluentUI.AspNetCore.Components.CommunicationToastContent 0%
Microsoft.FluentUI.AspNetCore.Components.ComponentParameters 16.6% 0%
Microsoft.FluentUI.AspNetCore.Components.Components.DateTime.RangeOfDates 100% 50%
Microsoft.FluentUI.AspNetCore.Components.Components.Tooltip.TooltipGlobalOp
tions
40%
Microsoft.FluentUI.AspNetCore.Components.Components.Tooltip.TooltipOptions 0%
Microsoft.FluentUI.AspNetCore.Components.Components.Tooltip.TooltipService 57.5% 30%
Microsoft.FluentUI.AspNetCore.Components.ConfirmationToast 0%
Microsoft.FluentUI.AspNetCore.Components.CountdownTimer 0% 0%
Microsoft.FluentUI.AspNetCore.Components.CustomEmoji 0% 0%
Microsoft.FluentUI.AspNetCore.Components.CustomIcon 0%
Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure.AsyncQuery
ExecutorSupplier
38.4% 50%
Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure.ColumnsCol
lectedNotifier`1
87.5% 50%
Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure.Defer 100%
Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure.DisplayAtt
ributeExtensions
66.6% 50%
Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure.InternalGr
idContext`1
90.4% 100%
Microsoft.FluentUI.AspNetCore.Components.DataGridCellFocusEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.DataGridRowFocusEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.DialogEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.DialogHelper 0%
Microsoft.FluentUI.AspNetCore.Components.DialogInstance 86.6% 75%
Microsoft.FluentUI.AspNetCore.Components.DialogParameters 91.1% 100%
Microsoft.FluentUI.AspNetCore.Components.DialogParameters`1 100%
Microsoft.FluentUI.AspNetCore.Components.DialogReference 36.3% 37.5%
Microsoft.FluentUI.AspNetCore.Components.DialogResult 0% 0%
Microsoft.FluentUI.AspNetCore.Components.DialogService 4.1% 2.6%
Microsoft.FluentUI.AspNetCore.Components.Emoji 0% 0%
Microsoft.FluentUI.AspNetCore.Components.EmojiCompress 0% 0%
Microsoft.FluentUI.AspNetCore.Components.EmojiExtensions 0% 0%
Microsoft.FluentUI.AspNetCore.Components.EmojiInfo 0%
Microsoft.FluentUI.AspNetCore.Components.Extensions.AdditionalAttributesExt
ensions
100% 100%
Microsoft.FluentUI.AspNetCore.Components.Extensions.BooleanExtensions 100% 100%
Microsoft.FluentUI.AspNetCore.Components.Extensions.DateTimeExtensions 81.2% 85%
Microsoft.FluentUI.AspNetCore.Components.Extensions.EnumExtensions 70.5% 59%
Microsoft.FluentUI.AspNetCore.Components.Extensions.FluentInputExtensions 25.9% 16.6%
Microsoft.FluentUI.AspNetCore.Components.Extensions.UrlFormatterExtensions 100% 75%
Microsoft.FluentUI.AspNetCore.Components.FluentAccessibilityStatus 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentAccordion 59.2% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentAccordionItem 83.7% 63.6%
Microsoft.FluentUI.AspNetCore.Components.FluentAnchor 90% 67.8%
Microsoft.FluentUI.AspNetCore.Components.FluentAnchoredRegion 87.7% 60%
Microsoft.FluentUI.AspNetCore.Components.FluentAppBar 64.6% 42.1%
Microsoft.FluentUI.AspNetCore.Components.FluentAppBarItem 85.2% 60%
Microsoft.FluentUI.AspNetCore.Components.FluentAutocomplete`1 85.7% 71.8%
Microsoft.FluentUI.AspNetCore.Components.FluentBadge 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentBodyContent 100%
Microsoft.FluentUI.AspNetCore.Components.FluentBreadcrumb 100%
Microsoft.FluentUI.AspNetCore.Components.FluentBreadcrumbItem 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentButton 84.3% 64.5%
Microsoft.FluentUI.AspNetCore.Components.FluentCalendar 83.4% 78.3%
Microsoft.FluentUI.AspNetCore.Components.FluentCalendarBase 93.7% 81.2%
Microsoft.FluentUI.AspNetCore.Components.FluentCalendarDay 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentCalendarMonth 92.3% 64.2%
Microsoft.FluentUI.AspNetCore.Components.FluentCalendarYear 84.6% 58.3%
Microsoft.FluentUI.AspNetCore.Components.FluentCard 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentCheckbox 91.1% 87%
Microsoft.FluentUI.AspNetCore.Components.FluentCollapsibleRegion 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentCombobox`1 69% 57.6%
Microsoft.FluentUI.AspNetCore.Components.FluentComponentBase 90.9% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentCounterBadge 92.3% 84.8%
Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1 56.5% 49%
Microsoft.FluentUI.AspNetCore.Components.FluentDataGridCell`1 80% 73.9%
Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1 56.2% 37.5%
Microsoft.FluentUI.AspNetCore.Components.FluentDatePicker 81.8% 51.9%
Microsoft.FluentUI.AspNetCore.Components.FluentDesignSystemProvider 100% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentDesignTheme 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentDialog 57.3% 60%
Microsoft.FluentUI.AspNetCore.Components.FluentDialogBody 100%
Microsoft.FluentUI.AspNetCore.Components.FluentDialogFooter 66.6% 44.1%
Microsoft.FluentUI.AspNetCore.Components.FluentDialogHeader 85.1% 75%
Microsoft.FluentUI.AspNetCore.Components.FluentDialogProvider 59.2% 57.1%
Microsoft.FluentUI.AspNetCore.Components.FluentDivider 86.9% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentDragContainer`1 71.4%
Microsoft.FluentUI.AspNetCore.Components.FluentDragEventArgs`1 0%
Microsoft.FluentUI.AspNetCore.Components.FluentDropZone`1 22.2% 4.3%
Microsoft.FluentUI.AspNetCore.Components.FluentEditForm 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentEmoji`1 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentFlipper 100%
Microsoft.FluentUI.AspNetCore.Components.FluentFooter 100%
Microsoft.FluentUI.AspNetCore.Components.FluentGrid 72.2% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentGridItem 87.5% 82.5%
Microsoft.FluentUI.AspNetCore.Components.FluentHeader 100%
Microsoft.FluentUI.AspNetCore.Components.FluentHighlighter 80% 20%
Microsoft.FluentUI.AspNetCore.Components.FluentHorizontalScroll 60.6% 20%
Microsoft.FluentUI.AspNetCore.Components.FluentIcon`1 88.3% 81.2%
Microsoft.FluentUI.AspNetCore.Components.FluentInputBase`1 69% 61.2%
Microsoft.FluentUI.AspNetCore.Components.FluentInputFile 90% 79.6%
Microsoft.FluentUI.AspNetCore.Components.FluentInputFileBuffer 100%
Microsoft.FluentUI.AspNetCore.Components.FluentInputFileEventArgs 92.3%
Microsoft.FluentUI.AspNetCore.Components.FluentInputLabel 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentKeyCode 88.6% 90%
Microsoft.FluentUI.AspNetCore.Components.FluentKeyCodeEventArgs 100% 75%
Microsoft.FluentUI.AspNetCore.Components.FluentKeyCodeProvider 40% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentLabel 98% 88.8%
Microsoft.FluentUI.AspNetCore.Components.FluentLayout 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentListbox`1 94.4% 83.3%
Microsoft.FluentUI.AspNetCore.Components.FluentMain 100%
Microsoft.FluentUI.AspNetCore.Components.FluentMainLayout 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentMenu 60.4% 51.3%
Microsoft.FluentUI.AspNetCore.Components.FluentMenuButton 73.1% 25%
Microsoft.FluentUI.AspNetCore.Components.FluentMenuItem 74% 41.6%
Microsoft.FluentUI.AspNetCore.Components.FluentMenuProvider 95.2% 83.3%
Microsoft.FluentUI.AspNetCore.Components.FluentMessageBar 48.7% 23.9%
Microsoft.FluentUI.AspNetCore.Components.FluentMessageBarProvider 70.4% 59%
Microsoft.FluentUI.AspNetCore.Components.FluentMultiSplitter 81.7% 66.6%
Microsoft.FluentUI.AspNetCore.Components.FluentMultiSplitterEventArgs 100%
Microsoft.FluentUI.AspNetCore.Components.FluentMultiSplitterPane 97.1% 91%
Microsoft.FluentUI.AspNetCore.Components.FluentMultiSplitterResizeEventArgs 100%
Microsoft.FluentUI.AspNetCore.Components.FluentNavBase 55.1% 16.6%
Microsoft.FluentUI.AspNetCore.Components.FluentNavGroup 62.3% 35.4%
Microsoft.FluentUI.AspNetCore.Components.FluentNavLink 55.2% 40.6%
Microsoft.FluentUI.AspNetCore.Components.FluentNavMenu 61.1% 33.3%
Microsoft.FluentUI.AspNetCore.Components.FluentNavMenuGroup 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentNavMenuItemBase 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentNavMenuLink 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentNavMenuTree 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentNumberField`1 63.8% 55.1%
Microsoft.FluentUI.AspNetCore.Components.FluentOption`1 80% 61.5%
Microsoft.FluentUI.AspNetCore.Components.FluentOverflow 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentOverflowItem 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentOverlay 74% 62%
Microsoft.FluentUI.AspNetCore.Components.FluentPageScript 100%
Microsoft.FluentUI.AspNetCore.Components.FluentPaginator 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentPersona 100% 78.1%
Microsoft.FluentUI.AspNetCore.Components.FluentPopover 78.4% 65.9%
Microsoft.FluentUI.AspNetCore.Components.FluentPresenceBadge 60.9% 29.1%
Microsoft.FluentUI.AspNetCore.Components.FluentProfileMenu 100% 100%
Microsoft.FluentUI.AspNetCore.Components.FluentProgress 81.2% 68.1%
Microsoft.FluentUI.AspNetCore.Components.FluentProgressRing 97.6% 92.8%
Microsoft.FluentUI.AspNetCore.Components.FluentPullToRefresh 94% 89.2%
Microsoft.FluentUI.AspNetCore.Components.FluentRadio`1 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentRadioContext 70% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentRadioGroup`1 77.7% 16.6%
Microsoft.FluentUI.AspNetCore.Components.FluentRating 76.4% 78.2%
Microsoft.FluentUI.AspNetCore.Components.FluentSearch 88.5% 83.3%
Microsoft.FluentUI.AspNetCore.Components.FluentSelect`1 96.4% 90%
Microsoft.FluentUI.AspNetCore.Components.FluentSkeleton 40.9% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentSlider`1 84.7% 68.4%
Microsoft.FluentUI.AspNetCore.Components.FluentSliderLabel`1 65.8% 33.3%
Microsoft.FluentUI.AspNetCore.Components.FluentSortableList`1 88.3% 67.8%
Microsoft.FluentUI.AspNetCore.Components.FluentSortableListEventArgs 83.3%
Microsoft.FluentUI.AspNetCore.Components.FluentSpacer 100% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentSplashScreen 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentSplitter 70.7% 40%
Microsoft.FluentUI.AspNetCore.Components.FluentStack 82.9% 33.3%
Microsoft.FluentUI.AspNetCore.Components.FluentSwitch 82.6% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentTab 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentTabs 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentTextArea 85%
Microsoft.FluentUI.AspNetCore.Components.FluentTextField 88.8% 60%
Microsoft.FluentUI.AspNetCore.Components.FluentTimePicker 83.3% 58.3%
Microsoft.FluentUI.AspNetCore.Components.FluentToast 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentToastProvider 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentToolbar 68.9% 50%
Microsoft.FluentUI.AspNetCore.Components.FluentTooltip 68.9% 72.7%
Microsoft.FluentUI.AspNetCore.Components.FluentTooltipProvider 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem 89.4% 77.7%
Microsoft.FluentUI.AspNetCore.Components.FluentTreeView 79.7% 65.6%
Microsoft.FluentUI.AspNetCore.Components.FluentValidationMessage`1 0% 0%
Microsoft.FluentUI.AspNetCore.Components.FluentValidationSummary 100% 87.5%
Microsoft.FluentUI.AspNetCore.Components.FluentWizard 96% 86.8%
Microsoft.FluentUI.AspNetCore.Components.FluentWizardStep 95.8% 88.3%
Microsoft.FluentUI.AspNetCore.Components.FluentWizardStepArgs 100%
Microsoft.FluentUI.AspNetCore.Components.FluentWizardStepChangeEventArgs 100%
Microsoft.FluentUI.AspNetCore.Components.GlobalState 31.8% 50%
Microsoft.FluentUI.AspNetCore.Components.GridItemsProviderRequest`1 54.5% 20.8%
Microsoft.FluentUI.AspNetCore.Components.GridItemsProviderResult 100%
Microsoft.FluentUI.AspNetCore.Components.GridItemsProviderResult`1 100%
Microsoft.FluentUI.AspNetCore.Components.GridSort`1 35.1% 25.9%
Microsoft.FluentUI.AspNetCore.Components.HeaderFooterContent`1 100% 50%
Microsoft.FluentUI.AspNetCore.Components.HierarchicalGridItem`2 0% 0%
Microsoft.FluentUI.AspNetCore.Components.HierarchicalGridUtilities 0% 0%
Microsoft.FluentUI.AspNetCore.Components.HorizontalScrollEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.Icon 83.7% 91.1%
Microsoft.FluentUI.AspNetCore.Components.IconFromImage 100%
Microsoft.FluentUI.AspNetCore.Components.IconInfo 100%
Microsoft.FluentUI.AspNetCore.Components.IconsExtensions 0% 0%
Microsoft.FluentUI.AspNetCore.Components.Identifier 66.6% 62.5%
Microsoft.FluentUI.AspNetCore.Components.IdentifierContext 66.6% 41.6%
Microsoft.FluentUI.AspNetCore.Components.IDialogService 0%
Microsoft.FluentUI.AspNetCore.Components.INavMenuItemsOwner 0%
Microsoft.FluentUI.AspNetCore.Components.Infrastructure.EventCallbackSubscr
ibable`1
100% 100%
Microsoft.FluentUI.AspNetCore.Components.Infrastructure.EventCallbackSubscr
iber`1
100% 87.5%
Microsoft.FluentUI.AspNetCore.Components.InputHelpers`1 62.1% 48.6%
Microsoft.FluentUI.AspNetCore.Components.InternalAppBarContext 100% 100%
Microsoft.FluentUI.AspNetCore.Components.InternalDialogContext 80%
Microsoft.FluentUI.AspNetCore.Components.InternalListContext`1 80% 66.6%
Microsoft.FluentUI.AspNetCore.Components.InternalToastContext 0%
Microsoft.FluentUI.AspNetCore.Components.KeyCodeService 60.3% 28.5%
Microsoft.FluentUI.AspNetCore.Components.KeyDown 0% 0%
Microsoft.FluentUI.AspNetCore.Components.LibraryConfiguration 88.8% 50%
Microsoft.FluentUI.AspNetCore.Components.ListComponentBase`1 61.3% 62.5%
Microsoft.FluentUI.AspNetCore.Components.LoadedEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.LuminanceChangedEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.MenuChangeEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.MenuService 63.8% 0%
Microsoft.FluentUI.AspNetCore.Components.Message 51.6% 0%
Microsoft.FluentUI.AspNetCore.Components.MessageBox 50% 0%
Microsoft.FluentUI.AspNetCore.Components.MessageBoxContent 0%
Microsoft.FluentUI.AspNetCore.Components.MessageOptions 78.5%
Microsoft.FluentUI.AspNetCore.Components.MessageService 29.4% 26.9%
Microsoft.FluentUI.AspNetCore.Components.NavMenuActionArgs 0% 0%
Microsoft.FluentUI.AspNetCore.Components.OfficeColorUtilities 0%
Microsoft.FluentUI.AspNetCore.Components.Option`1 0%
Microsoft.FluentUI.AspNetCore.Components.OptionsSearchEventArgs`1 100%
Microsoft.FluentUI.AspNetCore.Components.OverflowItem 100%
Microsoft.FluentUI.AspNetCore.Components.PaginationState 59% 43.7%
Microsoft.FluentUI.AspNetCore.Components.ProgressFileDetails 100%
Microsoft.FluentUI.AspNetCore.Components.ProgressToast 0% 0%
Microsoft.FluentUI.AspNetCore.Components.ProgressToastContent 0%
Microsoft.FluentUI.AspNetCore.Components.PropertyColumn`2 92.5% 71.7%
Microsoft.FluentUI.AspNetCore.Components.RenderFragmentDialog 100%
Microsoft.FluentUI.AspNetCore.Components.Resources.TimeAgoResource 76.1% 100%
Microsoft.FluentUI.AspNetCore.Components.SelectAllTemplateArgs 100%
Microsoft.FluentUI.AspNetCore.Components.SelectColumn`1 86.6% 82.1%
Microsoft.FluentUI.AspNetCore.Components.SelectDatesHoverEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.ServiceCollectionExtensions 59.2% 66.6%
Microsoft.FluentUI.AspNetCore.Components.SortedProperty 0%
Microsoft.FluentUI.AspNetCore.Components.SplashScreenContent 0% 0%
Microsoft.FluentUI.AspNetCore.Components.SplitterCollapsedEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.SplitterResizedEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.StandardLuminanceExtensions 0% 0%
Microsoft.FluentUI.AspNetCore.Components.TabChangeEventArgs 0%
Microsoft.FluentUI.AspNetCore.Components.TemplateColumn`1 83.3% 0%
Microsoft.FluentUI.AspNetCore.Components.TimeAgoOptions 100%
Microsoft.FluentUI.AspNetCore.Components.ToastInstance 0% 0%
Microsoft.FluentUI.AspNetCore.Components.ToastParameters 0%
Microsoft.FluentUI.AspNetCore.Components.ToastParameters`1 0%
Microsoft.FluentUI.AspNetCore.Components.ToastResult 0% 0%
Microsoft.FluentUI.AspNetCore.Components.ToastService 0% 0%
Microsoft.FluentUI.AspNetCore.Components.TreeChangeEventArgs 100%
Microsoft.FluentUI.AspNetCore.Components.TreeViewItem 100%
Microsoft.FluentUI.AspNetCore.Components.TreeViewItemExpandedEventArgs 100%
Microsoft.FluentUI.AspNetCore.Components.UploadedFileDetails 0%
Microsoft.FluentUI.AspNetCore.Components.Utilities.CssBuilder 100% 100%
Microsoft.FluentUI.AspNetCore.Components.Utilities.InlineStyleBuilder 96.4% 87.5%
Microsoft.FluentUI.AspNetCore.Components.Utilities.InternalDebounce.Debounc
eAction
52.3% 18.7%
Microsoft.FluentUI.AspNetCore.Components.Utilities.InternalDebounce.Debounc
eTask
0% 0%
Microsoft.FluentUI.AspNetCore.Components.Utilities.InternalDebounce.Dispatc
herTimerExtensions
82.9% 70%
Microsoft.FluentUI.AspNetCore.Components.Utilities.JSModule 0% 0%
Microsoft.FluentUI.AspNetCore.Components.Utilities.RangeOf`1 96.7% 94.4%
Microsoft.FluentUI.AspNetCore.Components.Utilities.Splitter 82.8% 81.8%
Microsoft.FluentUI.AspNetCore.Components.Utilities.StyleBuilder 100% 91.6%
Microsoft.FluentUI.AspNetCore.Components.ZIndex 100%
System.Text.RegularExpressions.Generated 76.4% 53.1%

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the DataGrid JavaScript interop by enhancing abort controller management for proper cleanup of event listeners, improving keyboard event handling for closing popups with the Escape key, and fixing registry persistence to handle re-initialization scenarios.

Changes:

  • Enhanced AbortController management to clean up resize event listeners when columns change
  • Added Escape key handling at the body level to close column options and resize popups
  • Improved grid registry to update existing entries instead of creating duplicates

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +60 to 64
if (columnResizeElement) {
if (event.key === "ArrowRight" || event.key === "ArrowLeft" || event.key === "ArrowDown" || event.key === "ArrowUp") {
event.stopPropagation();
}
if (event.key === "Escape") {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
gridElement.focus();
return;
}
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the contains(event.target) check changes the behavior significantly. Previously, arrow key propagation was only stopped when the event target was inside the column resize element. Now it stops propagation whenever the column resize element merely exists in the DOM, regardless of whether the event originated from within it. This will incorrectly prevent arrow key navigation when column resize is open but focus is elsewhere in the grid.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +39
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
}
const columnResizeElement = gridElement?.querySelector('.col-resize');
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
gridElement.focus();
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When multiple grids exist on the page and Escape is pressed, all grids' bodyKeyDownHandler functions will execute. Each grid that has column options or resize elements open will dispatch close events and call gridElement.focus(). This can cause a focus race condition where the last grid's handler steals focus, even if the user intended to close a popup on a different grid. Consider checking if the event originated from within the specific grid's DOM or if the popup element is currently focused before calling focus.

Suggested change
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
}
const columnResizeElement = gridElement?.querySelector('.col-resize');
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
gridElement.focus();
const columnResizeElement = gridElement?.querySelector('.col-resize');
// Determine whether this Escape event is relevant to this grid or its popups
const eventPath = typeof event.composedPath === "function" ? event.composedPath() : [];
const eventOriginatesFromThisGrid = eventPath && eventPath.indexOf(gridElement) >= 0;
const activeElement = document.activeElement;
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
const optionsHasFocus = columnOptionsElement.contains(activeElement);
if (eventOriginatesFromThisGrid || optionsHasFocus) {
gridElement.focus();
}
}
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
const resizeHasFocus = columnResizeElement.contains(activeElement);
if (eventOriginatesFromThisGrid || resizeHasFocus) {
gridElement.focus();
}

Copilot uses AI. Check for mistakes.
grid.resizeController.abort();
}

const localController = new AbortController();
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an external signal is provided (e.g., from the init function), a localController is created on line 190 but never used because effectiveSignal will be the external signal. Additionally, line 250 stores undefined for resizeController when an external signal is used. This means when enableColumnResizing is called again (e.g., when columns change), lines 186-188 attempt to abort a controller that is always undefined in this scenario. While the old resize handle divs are removed (line 223) which cleans up their listeners, the localController serves no purpose and creates unnecessary overhead. Consider only creating localController when no external signal is provided.

Suggested change
const localController = new AbortController();
const localController = signal ? null : new AbortController();

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +38
const columnOptionsElement = gridElement?.querySelector('.col-options');
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
}
const columnResizeElement = gridElement?.querySelector('.col-resize');
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handler calls gridElement.focus() on both lines 34 and 39 when both column options and column resize elements exist simultaneously. This results in redundant focus calls. Consider checking if either element exists first, dispatching the appropriate close events, and then calling focus once at the end.

Suggested change
const columnOptionsElement = gridElement?.querySelector('.col-options');
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
}
const columnResizeElement = gridElement?.querySelector('.col-resize');
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
let shouldFocus = false;
const columnOptionsElement = gridElement?.querySelector('.col-options');
if (columnOptionsElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
shouldFocus = true;
}
const columnResizeElement = gridElement?.querySelector('.col-resize');
if (columnResizeElement) {
gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true }));
shouldFocus = true;
}
if (shouldFocus) {

Copilot uses AI. Check for mistakes.
Comment on lines +52 to 56
if (columnOptionsElement) {
if (event.key === "ArrowRight" || event.key === "ArrowLeft" || event.key === "ArrowDown" || event.key === "ArrowUp") {
event.stopPropagation();
}
if (event.key === "Escape") {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
return;
}
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the contains(event.target) check changes the behavior significantly. Previously, arrow key propagation was only stopped when the event target was inside the column options element. Now it stops propagation whenever the column options element merely exists in the DOM, regardless of whether the event originated from within it. This will incorrectly prevent arrow key navigation when column options are open but focus is elsewhere in the grid.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants