feat: add collapsible wallet sections to Accounts page#39645
feat: add collapsible wallet sections to Accounts page#39645georgewrmarshall merged 3 commits intomainfrom
Conversation
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
✨ Files requiring CODEOWNER review ✨🔑 @MetaMask/accounts-engineers (2 files, +206 -10)
|
Builds ready [b70d5bb]
UI Startup Metrics (1350 ± 128 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Builds ready [eccfa16]
UI Startup Metrics (1325 ± 118 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
… triggers unrelated background warnings
| "ui/components/multichain-accounts/multichain-account-list/multichain-account-list.test.tsx": { | ||
| "MetaMask: Background connection not initialized": 66, | ||
| "Reselect: Identity function warnings": 2, | ||
| "MetaMask: Background connection not initialized": 73, |
There was a problem hiding this comment.
Updated baseline to reflect console warnings from new comprehensive test coverage. The +7 'Background connection not initialized' warnings are expected in isolated component tests and similar to other test files in the codebase. The tests function correctly - these are infrastructure warnings, not code issues.
| const [isHiddenAccountsExpanded, setIsHiddenAccountsExpanded] = | ||
| useState(false); | ||
|
|
||
| const [collapsedSectionKeys, setCollapsedSectionKeys] = useState<Set<string>>( |
There was a problem hiding this comment.
State management for tracking which sections are collapsed. Using a Set for O(1) lookup performance when checking if a section is expanded.
| () => new Set(), | ||
| ); | ||
|
|
||
| const toggleSectionExpanded = useCallback((sectionKey: string) => { |
There was a problem hiding this comment.
Toggle function wrapped in useCallback to prevent unnecessary re-renders. It adds/removes the sectionKey from the Set to track collapsed state.
|
|
||
| type ListItem = | ||
| | { type: 'header'; key: string; text: string; testId?: string } | ||
| | { |
There was a problem hiding this comment.
Extended the ListItem header type to support collapsible sections. Added sectionKey for identifying which section to collapse, isCollapsible flag, and isExpanded state.
|
|
||
| // Render pinned section (if there are any pinned accounts) | ||
| if (pinnedGroups.length > 0) { | ||
| const pinnedSectionKey = 'pinned'; |
There was a problem hiding this comment.
Pinned section is now collapsible. Only render pinned accounts when the section is expanded. The section is expanded by default (not in collapsedSectionKeys Set).
|
|
||
| if (accounts.length > 0) { | ||
| if (shouldShowWalletHeaders) { | ||
| const walletSectionKey = `wallet-${walletId}`; |
There was a problem hiding this comment.
Each wallet section gets a unique sectionKey (wallet-{walletId}) for collapse tracking. When collapsed, accounts are not rendered at all, improving performance. Early return after adding header + accounts prevents duplicate rendering.
| isInSearchMode, | ||
| displayWalletHeader, | ||
| isHiddenAccountsExpanded, | ||
| collapsedSectionKeys, |
There was a problem hiding this comment.
Added collapsedSectionKeys to the useMemo dependency array to ensure the list re-renders when sections are collapsed/expanded.
| keyExtractor={(item) => item.key} | ||
| renderItem={({ item }) => { | ||
| if (item.type === 'header') { | ||
| if (item.isCollapsible && item.sectionKey) { |
There was a problem hiding this comment.
Collapsible header rendering: When a header is marked as collapsible, it becomes a clickable button with an arrow icon that rotates based on expanded state. Uses aria-expanded for accessibility.
| getScrollElement: () => | ||
| disabled ? null : (scrollContainerRef?.current ?? null), | ||
| estimateSize: () => estimatedItemSize, | ||
| getItemKey: (index) => |
There was a problem hiding this comment.
Fixed VirtualizedList to properly use keyExtractor for stable keys. Previously used index which caused issues when items were dynamically added/removed. Now uses the keyExtractor result (or virtualItem.key) for both getItemKey and the rendered key prop.
| }); | ||
| }); | ||
|
|
||
| describe('Collapsible section headers', () => { |
There was a problem hiding this comment.
Comprehensive test coverage for the new collapsible section functionality. Tests verify that wallet headers and pinned sections can be collapsed independently, accounts disappear when collapsed, and multiple sections maintain their own state.
Builds ready [3e086d4]
UI Startup Metrics (1361 ± 114 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
ccharly
left a comment
There was a problem hiding this comment.
Really nice 💪
Found a small edge-case though, IDK what was the intended behavior for this but, if you (with 1 wallet):
- Pin "Account 1"
- Collapse "Wallet 1"
- Unpin "Account 1"
- You will see both accounts now, since there's no section anymore
- Re-pin "Account 1"
- "Wallet 1" will still be collapsed (since I think we're not clearing the set when re-using the default layout with no sections)
That's pretty edge-case IMO, but just wanted to share that just in case this was not the expected behavior!
Screen.Recording.2026-01-30.at.10.28.31.mov
Great catch @ccharly! I agree I think it would be nice if it defaulted back to being expanded. I'll look into this |
|
@n3ps @georgewrmarshall @ccharly should this be merged? |
Description
This PR adds collapsible wallet sections to the MultichainAccountList component on the Accounts page, allowing users to collapse and expand wallet sections (including pinned accounts) to better organize their accounts view.
Currently, users with multiple wallets and many accounts have limited ability to manage the visual organization of their accounts. This PR extends the existing collapse functionality (previously only available for hidden accounts) to all wallet sections and the pinned accounts section.
Implementation approach:
collapsedSectionKeysSet to track which sections are collapsedheaderListItem type to support collapsible sections withsectionKey,isCollapsible, andisExpandedpropertiesgetItemKeyconfig to ensure proper React reconciliation during collapse/expandTechnical details:
getItemKeyin virtualizer config for stable keys during list changesChangelog
CHANGELOG entry: Added ability to collapse wallet sections in the Accounts page
Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/MDP-678
Supersedes: #39583
Manual testing steps
Screenshots/Recordings
Before
Wallet headers were not interactive - all wallets were always expanded. Only the hidden accounts section could be collapsed.
before720.mov
After
All section headers (Pinned, Wallet 1, Wallet 2, etc.) are now clickable buttons with collapse/expand arrows. Each section can be independently collapsed to hide its accounts.
after720.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Medium risk because it changes list rendering/state and virtualized keying, which could cause subtle UI/scroll/reconciliation issues when collapsing/expanding sections.
Overview
Adds collapsible section headers to
MultichainAccountListfor both the Pinned section and each wallet section, tracking collapsed state via acollapsedSectionKeysset and conditionally omitting section items from the list data.Updates header rendering to be a clickable button with
aria-expandedand an up/down arrow indicator, and adds unit tests covering wallet, pinned, and independent multi-section collapse behavior.Improves
VirtualizedListstability by wiringkeyExtractorintouseVirtualizerviagetItemKeyand using the virtualizer-provided key when no extractor is given.Written by Cursor Bugbot for commit 3e086d4. This will update automatically on new commits. Configure here.