You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MudBlazor 9.6.0 (MudBlazor#13288) made the tab panel wrapper <div role="tabpanel"> layout-transparent: inactive panels are display: none, the active panel is display: contents — it no longer generates a layout box. Every height/overflow/display rule app.css applied to .mud-tab-panel was silently ignored, which broke all scrolling on narrow screens (reported in #1030 as "the edit window isn't appearing"; the edit form was clipped inside an unscrollable panel).
PR #1037 (commit 7164068) shipped a compatibility shim that pins the active panel back to the 9.5.x block box:
This works (verified end-to-end), but it fights MudBlazor's new contract — don't style the panel wrapper; style your own content element or the panels container — and it depends on MudBlazor's internal class names plus winning a (0,4,0) specificity tie by file order. The next MudBlazor bump can break it again the same way 9.6.0 did. This issue tracks the proper migration so the shim can be deleted.
Current wrapper-dependent rules (the migration inventory)
Also: the comment near line ~1109 references the panel's overflow-x: hidden — update it when the rule moves.
Tab wrapper inventory (SaveFileComponent.razor)
Tabs that already have a dedicated content-wrapper class: Party/Box (party-box-tab-content), Trainer (trainer-tab-content), Feebas (feebas-tab-content), Teams (teams-tab-content), Bank (bank-tab-content), Trade (trade-tab-content), Pokédex (pokedex-tab-content, inside PokedexTab).
Tabs with no wrapper class (just div.mt-3 or the bare component): Bag, Mystery Gifts, Wonder Cards, Records, RTC, Legality Report, Search, Encounter DB, Batch Editor.
Implementation plan
Strategy: make .mud-tabs-panels the layout/scroll container (recommended — under display: contents the tab content already behaves as a direct child of it, and since KeepPanelsAlive is not used, only the active tab's content is ever in the DOM).
Give the panels container a definite height. MudBlazor's horizontal .mud-tabs root is not a flex container, so add at both breakpoints:
(.save-file-outer-tabs already gets flex: 1; min-height: 0; overflow: hidden from its own parent cascade — keep that.) Verify the tab header bar (.mud-tabs-tabbar) keeps its natural height as the non-growing flex child.
Narrow screens (<1280px): move the default scroll role from the panel to the container. Replace the > .mud-tab-panel { height:100%; overflow-y:auto; overflow-x:hidden } rule with:
Tabs without wrapper classes then need no CSS at all — their content scrolls in the container. This removes the need to invent wrapper classes for Bag/Mystery Gifts/Wonder Cards/Records/RTC/Legality/Search/Encounter DB/Batch Editor.
Narrow screens: Pokédex opt-out moves up a level. The Virtualize component needs a definite, viewport-bounded height, so the container must not scroll when the Pokédex tab is active. The panel wrapper is still present in the DOM tree (it just has no box), so :has() still matches through it:
.pokedex-tab-content { height: 100%; overflow: hidden } (global, existing) keeps working because its containing block is now the flexed container. Confirm the virtualized species list still renders full-length (the failure mode is it cutting off at ~106 rows).
Desktop (≥1280px): drop the panel clipping rule, keep clipping on the container. The container already has overflow: hidden at this breakpoint; delete the > .mud-tab-panel { height: 100%; overflow: hidden } rule. Per-tab wrappers (trade-, feebas-, teams-, trainer-tab-content, all height: 100%; overflow-y: auto) now resolve their percentage height against the flexed .mud-tabs-panels from step 1 — this is the part most likely to shift pixels, since their old containing block was the panel box. Verify each.
Desktop: Bank flex cascade moves up a level, mirroring step 3:
.bank-tab-content { flex: 1; min-height: 0; … } (existing) then participates directly in the container's flex layout — with display: contents on the wrapper this actually gets simpler than today.
Inner edit-form tabs need no migration — .edit-form-tabs .mud-tabs-panels rules already style the container, not the panel wrapper. Sanity-check only.
Delete the shim (the display: block override near the top of app.css) and its comment, plus the two now-dead :has() panel rules. Update the stale comment near line ~1109.
Watch for specificity ties: MudBlazor's own .mud-tabs-panels.mud-tabs-vertical { display: flex } and the transition on .mud-tabs-panels should be unaffected, but diff computed styles before/after on the container to be sure.
Verification matrix
Playwright against a local Debug build (the method used to verify PR #1037: load TestFiles/Test-Save-White-2.sav, drive tabs via JS clicks, assert scrollHeight/scrollTop movement and element visibility):
Per tab: bottom of content reachable by scroll; no double scrollbars; no horizontal scroll on phone.
Critical flows: select a box Pokémon on phone → edit form scrolls into view (the [Feedback] Please remove auto-rotate or at least an option to disable it. Thanks. #1030 regression); Pokédex species list renders full-length on phone and desktop; Bank card grid fills remaining height on desktop; Search/Encounter DB action buttons pinned visible at the bottom; Trainer tab scrolls on phone and short desktop windows.
Real device: one pass on an actual iPhone (Safari + installed PWA) since the original report was iOS.
Acceptance criteria
No app.css rule targets .mud-tab-panel inside .save-file-outer-tabs (wrapper is layout-transparent, per the MudBlazor 9.6 contract)
The display: block shim is deleted
Full verification matrix passes
Comments in app.css updated to describe the container-based cascade
Optional follow-up
Raise upstream on MudBlazor#13288 that the change silently breaks consumer CSS targeting the panel wrapper in a minor release, and that display: contents on an element with role="tabpanel" has a history of accessibility-tree bugs in some browsers.
Background
MudBlazor 9.6.0 (MudBlazor#13288) made the tab panel wrapper
<div role="tabpanel">layout-transparent: inactive panels aredisplay: none, the active panel isdisplay: contents— it no longer generates a layout box. Everyheight/overflow/displayruleapp.cssapplied to.mud-tab-panelwas silently ignored, which broke all scrolling on narrow screens (reported in #1030 as "the edit window isn't appearing"; the edit form was clipped inside an unscrollable panel).PR #1037 (commit 7164068) shipped a compatibility shim that pins the active panel back to the 9.5.x block box:
This works (verified end-to-end), but it fights MudBlazor's new contract — don't style the panel wrapper; style your own content element or the panels container — and it depends on MudBlazor's internal class names plus winning a
(0,4,0)specificity tie by file order. The next MudBlazor bump can break it again the same way 9.6.0 did. This issue tracks the proper migration so the shim can be deleted.Current wrapper-dependent rules (the migration inventory)
All in
Pkmds.Rcl/wwwroot/css/app.css:.mud-tabs-panels > .mud-tab-panel.mud-tab-panel-active:not(...)→display: block.save-file-outer-tabs > .mud-tabs-panels > .mud-tab-panel→height: 100%; overflow: hidden… > .mud-tab-panel:has(.bank-tab-content)→display: flex; flex-direction: column… > .mud-tabs-panels > .mud-tab-panel→height: 100%; overflow-y: auto; overflow-x: hidden… > .mud-tab-panel:has(.pokedex-tab-content)→overflow: hidden; display: flex; flex-direction: columnAlso: the comment near line ~1109 references the panel's
overflow-x: hidden— update it when the rule moves.Tab wrapper inventory (
SaveFileComponent.razor)Tabs that already have a dedicated content-wrapper class: Party/Box (
party-box-tab-content), Trainer (trainer-tab-content), Feebas (feebas-tab-content), Teams (teams-tab-content), Bank (bank-tab-content), Trade (trade-tab-content), Pokédex (pokedex-tab-content, insidePokedexTab).Tabs with no wrapper class (just
div.mt-3or the bare component): Bag, Mystery Gifts, Wonder Cards, Records, RTC, Legality Report, Search, Encounter DB, Batch Editor.Implementation plan
Strategy: make
.mud-tabs-panelsthe layout/scroll container (recommended — underdisplay: contentsthe tab content already behaves as a direct child of it, and sinceKeepPanelsAliveis not used, only the active tab's content is ever in the DOM).Give the panels container a definite height. MudBlazor's horizontal
.mud-tabsroot is not a flex container, so add at both breakpoints:(
.save-file-outer-tabsalready getsflex: 1; min-height: 0; overflow: hiddenfrom its own parent cascade — keep that.) Verify the tab header bar (.mud-tabs-tabbar) keeps its natural height as the non-growing flex child.Narrow screens (<1280px): move the default scroll role from the panel to the container. Replace the
> .mud-tab-panel { height:100%; overflow-y:auto; overflow-x:hidden }rule with:Tabs without wrapper classes then need no CSS at all — their content scrolls in the container. This removes the need to invent wrapper classes for Bag/Mystery Gifts/Wonder Cards/Records/RTC/Legality/Search/Encounter DB/Batch Editor.
Narrow screens: Pokédex opt-out moves up a level. The Virtualize component needs a definite, viewport-bounded height, so the container must not scroll when the Pokédex tab is active. The panel wrapper is still present in the DOM tree (it just has no box), so
:has()still matches through it:.pokedex-tab-content { height: 100%; overflow: hidden }(global, existing) keeps working because its containing block is now the flexed container. Confirm the virtualized species list still renders full-length (the failure mode is it cutting off at ~106 rows).Desktop (≥1280px): drop the panel clipping rule, keep clipping on the container. The container already has
overflow: hiddenat this breakpoint; delete the> .mud-tab-panel { height: 100%; overflow: hidden }rule. Per-tab wrappers (trade-,feebas-,teams-,trainer-tab-content, allheight: 100%; overflow-y: auto) now resolve their percentage height against the flexed.mud-tabs-panelsfrom step 1 — this is the part most likely to shift pixels, since their old containing block was the panel box. Verify each.Desktop: Bank flex cascade moves up a level, mirroring step 3:
.bank-tab-content { flex: 1; min-height: 0; … }(existing) then participates directly in the container's flex layout — withdisplay: contentson the wrapper this actually gets simpler than today.Inner edit-form tabs need no migration —
.edit-form-tabs .mud-tabs-panelsrules already style the container, not the panel wrapper. Sanity-check only.Delete the shim (the
display: blockoverride near the top of app.css) and its comment, plus the two now-dead:has()panel rules. Update the stale comment near line ~1109.Watch for specificity ties: MudBlazor's own
.mud-tabs-panels.mud-tabs-vertical { display: flex }and the transition on.mud-tabs-panelsshould be unaffected, but diff computed styles before/after on the container to be sure.Verification matrix
Playwright against a local Debug build (the method used to verify PR #1037: load
TestFiles/Test-Save-White-2.sav, drive tabs via JS clicks, assertscrollHeight/scrollTopmovement and element visibility):Acceptance criteria
app.cssrule targets.mud-tab-panelinside.save-file-outer-tabs(wrapper is layout-transparent, per the MudBlazor 9.6 contract)display: blockshim is deletedOptional follow-up
Raise upstream on MudBlazor#13288 that the change silently breaks consumer CSS targeting the panel wrapper in a minor release, and that
display: contentson an element withrole="tabpanel"has a history of accessibility-tree bugs in some browsers.🤖 Generated with Claude Code
https://claude.ai/code/session_01AVBABqa4sjEdMCnKvshS1t