#13856·MudBlazor

Stop re-rendering content that didn't change during interactions

Author: danielchalmersCreated Sep 14, 2026Updated Sep 15, 2026
Labelsperformance

Spun off from #13737, which tracks how many components each item renders. This issue tracks how often content is rendered: interactions that rebuild content that didn't change. Key interceptor work is in #13855.

The usual cause is that a ChildContent parameter, a non-fixed cascade or a new delegate always counts as changed. When a component re-renders itself (opening, toggling, highlighting), everything under it rebuilds. bUnit's renderer doesn't show most of this, so every number below comes from a real browser.

Status by release

v9.9.0 (released 2026-08-24)

PR what
#13663 MudDataGrid: stop re-rendering the grid while typing in the column filter menu
#13678 MudDataGrid: remove a dead field that rendered every header cell twice
#13677 Localizer: stop components re-rendering when their localized text is unchanged

v9.10.0 (released 2026-09-13)

PR what
#13706 MudElement: capture element references without an extra render
#13730 MudSelect: skip the extra mount render when nothing resolves
#13732, fixed by #13791 MudTreeView: only re-render items whose state changed
#13734 MudChipSet: only re-render chips whose selection changed
#13736, fixed by #13790 MudTable: only re-render rows whose selection changed
#13742, reverted by #13744 MudRadioGroup: cascade itself as a fixed value (redone in #13798)
#13792, #13796 MudDataGrid: cell-edit, grouped-row and context-menu re-render overhead (#11860)

v9.11.0 (current)

Merged:

PR what
#13798 MudRadioGroup: cascade itself as a fixed value
#13862 MudDataGrid: opening a column filter menu doesn't re-render the grid. 100 rows: 393 -> 347 ms, 315 -> 52 renders
#13863 MudDataGrid: expanding a group renders only that group. 25 groups: 10-12 -> 3 ms
#13864 MudDataGrid: picking a filter-row value renders the grid once. 100 rows: 49 -> 36 ms
#13868 MudDatePicker: the year list renders markup, once. Open the year view 54 -> 20 ms, pick a year 49 -> 29 ms
#13851 MudSelect: options render once per open instead of on every self-render. Open 100 options 120 -> 53 ms, 1000 options 1196 -> 596 ms. Option content reading state changed without any render stays stale while open until the page renders.

An audit of every merged performance PR since v9.8.0 found stale content or behaviour regressions in a few of them, fixed by:

PR fixes
#13873 MudChipSet: chips ignored set parameter changes that came with a selection change (#13734)
#13874 MudDataGrid: the column filter menu stayed open after Enter or Escape with async filtering (#13663)
#13875 MudTimePicker and MudMenu: the browser context menu showed on .NET 8 and 9 (#13684, #13670)
#13876 MudDataGrid: GroupDefinition.Expanded was stale in group templates (#13863)
#13877 MudTreeView: runtime icon, ripple and expand trigger changes didn't reach items (#13732)
#13878, #13879 MudBreadcrumbs and MudExpansionPanels: older gaps of the same kind

v9.11.0 performance work is complete. More re-render work waits until v9.13.0 or later.

Built and not merged:

change scenario before after why
MudLayout and MudDrawerContainer: toggling a drawer doesn't rebuild the layout's content toggle a drawer in a layout of 200 components 41 ms 23 ms Dropped: content can go stale when a child component toggles the drawer.
#13858 MudTabs: panels render only when the tabs' parent renders or the active panel changes mount 12 tabs with KeepPanelsAlive 178 ms, 4198 renders 74 ms, 502 renders Closed: panel content can go stale when OnPreviewInteraction changes state and the active tab is clicked again.
#13867 MudCard: cascade the card as a fixed value type in a 12-field form inside a card 12 ms per key 8 ms per key Closed: every piece of card state its parts read would need its own named cascade, for about 4 ms per key.
MudDataGrid and MudTable: make row @key work sort 100 rows, MudDataGrid 127 ms 55 ms Held for v9.13.0 or later: row state starts following items, and keys depend on item equality.
sort 100 rows, MudTable 52 ms 36 ms

Notes:

  • Row keys: each row is its own render-tree region inside MudVirtualize, so @key never matches and moved rows are recreated on sort and filter. Repeated items must render without a key, or the page crashes with a duplicate key.
Measured and dropped for v9.11.0
idea measured
MudMenu: guard the items and fix the cascade 1-4 ms per interaction at 10 items, 7-14 ms at 50
MudSelect: its three renders while opening about 6 ms of a 46 ms open, no per-option cost
MudSelectItem: skip rendering the hidden shadow copies 100 fewer renders per multi-select toggle, 0 ms
MudAutocomplete: guard the result items 12 -> 9 ms per arrow key at 10 results; typing is dominated by the debounce
MudCollapse: don't re-render the content at the end of the transition about 10 ms on a nav group of 60 links, ranges overlap
MudExpansionPanel: guard the content no change; UpdateAllAsync re-rendering every panel is the cause
MudTabs: switching tabs 12-13 ms either way
MudInput and MudTextField: non-rendering key handlers at most 1 ms per key on WASM
MudFormComponent: skip the render when a field's validation messages didn't change 16 -> 15 ms per commit in a 20-field EditForm

v9.x (future)

More re-render work waits until the changes from v9.9.0 through v9.11.0 have proven stable, so the items below and the held row keys will probably land in v9.13.0 or later.

Found by render counts in the browser, not timed yet. Each needs a timing before it's worth a PR.

  • MudSwipeArea (and so MudCarousel) and MudColorPicker's spectrum re-render on every pointer move with no button pressed.
  • MudDropZone re-renders every item in every zone on drag start and drop (96 renders on drag start in a 64-zone chessboard).
  • MudAutocomplete destroys and rebuilds its result list right before closing when a result is clicked.
  • MudTimePicker re-renders all 25-37 of its number labels on every pointer down, drag step and click. Date and time pickers re-render on every key press, including keys that change nothing.
  • MudSnackbarProvider re-renders every visible snackbar when one is added, even when the new one is queued.
  • MudTimeline, MudCarousel and MudRating cascade themselves with IsFixed="false", so every render re-renders every item.
  • Docs site: every page navigation re-renders the whole left nav, about 290 components on Blazor Server.
  • MudExpansionPanels re-renders every panel when one toggles (UpdateAllAsync), 2N+5 component renders for N panels.
  • MudStepper re-renders every step title on each step change.

v10 (next breaking release)

  • Keep popover content mounted while it is closed. Today closing a MudSelect or MudMenu destroys its content and every open rebuilds it. Keeping it would make reopening nearly free, but closed popups would hold their DOM, which changes the markup. Not measured yet.
  • MudSelect without shadow items, tracked in #13737, also removes the renders of the hidden copies and the per-open shadow item rebuild #13851 needs.

Large option lists

A 1000-option MudSelect is not a design target. Past a few hundred options MudAutocomplete is the right component, as the Select docs say. <Virtualize> inside MudSelect breaks keyboard navigation and check state (#12998, #13561).

How it was measured

A probe build counted renders per component type in the browser. Timings are headless Chrome against the Debug WASM test viewer, median of 12 runs over 2 rounds, alternating builds. A ceiling build (the smallest change that removes the extra renders) was compared against the base. Proposed fixes get a shippable version, tests and a browser behaviour A/B against dev before a PR.