Skip to content

fix(ui): keep Activity tab underline in sync#30640

Merged
wachunei merged 2 commits into
mainfrom
fix/TMCU-755-activity-tab-underline-stuck-v2
May 26, 2026
Merged

fix(ui): keep Activity tab underline in sync#30640
wachunei merged 2 commits into
mainfrom
fix/TMCU-755-activity-tab-underline-stuck-v2

Conversation

@wachunei
Copy link
Copy Markdown
Member

@wachunei wachunei commented May 26, 2026

Description

Fixes the Activity tab underline getting stuck on the wrong tab after changing the network filter, when conditional tabs (e.g. Perps) are added or removed.

Detailed explanation (root cause and fix)

Root cause

The underline position is driven by measurements captured in tabLayouts.current and updated by onLayout callbacks in TabsBar.

When the set of tabs changes (for example, Perps becomes enabled/disabled after a network filter change), TabsBar was resetting tabLayouts.current with new Array(tabs.length). This produces a sparse array.

TabsBar then used Array.prototype.every(...) to determine that all tab layouts were available. On sparse arrays, every(...) skips holes, so the check could incorrectly return true even when only a subset of tab layouts had actually been measured.

That caused layoutsReady to become true prematurely and allowed animateToTab(...) to run against incomplete layout data. In the common failure case, the underline would animate to the last-measured tab and then refuse to move when the user switched back to a tab whose layout entry was still missing, leaving the underline stuck on the wrong tab.

Fix

This PR makes the layout readiness checks robust and ensures we re-measure after structural tab changes:

  1. Use dense arrays for layout resets

    • Replace new Array(n) with Array.from({ length: n }, () => undefined) so the array has no holes.
  2. Make "all measured" checks strict

    • Introduce areAllTabLayoutsMeasured(...), which requires layouts.length === tabCount and that every slot is defined with a positive width.
  3. Force re-measurement when tabs change

    • Add a layoutGeneration value that is incremented on structural tab changes and included in the Tab key so React remounts each Tab and reliably re-fires onLayout after add/remove.
  4. Recover underline position as soon as the active tab is measured

    • After storing a layout, if the active tab has a valid layout we schedule animateToTab(activeIdx) via requestAnimationFrame, so the underline updates promptly even while other tabs are still measuring.

What changed in practice

  • After a tab add/remove, the underline will only be considered ready once measurements exist for the relevant tab(s).
  • The active tab's underline can re-position as soon as that tab's layout is available, preventing the underline from vanishing or sticking during transitions.

Changelog

CHANGELOG entry: Fixed a bug where the Activity tab underline could get stuck on the wrong tab after changing networks.

Related issues

Fixes: #30365

Relates-to: https://consensyssoftware.atlassian.net/browse/TMCU-755

Manual testing steps

Feature: Activity tab underline stays in sync when tabs change

  Scenario: underline remains aligned after network filter changes tab set
    Given the user is on the Activity screen with multiple tabs visible (e.g. Transactions, Transfers, Perps, Predictions)
    And the tab underline is visible under the active tab

    When the user changes the network filter so a conditional tab is removed (e.g. Perps)
    Then the underline stays aligned with the currently selected tab

    When the user changes the network filter so the conditional tab is added back
    And the user switches between Transactions, Transfers, Perps, and Predictions
    Then the underline follows the active tab and does not get stuck on a different tab

Screenshots/Recordings

Before

Tab underline could remain under the wrong tab (e.g. Predictions) while Transactions content was shown, after changing the network filter.

After

Tab underline stays aligned with the active tab when conditional tabs are added or removed.

tab_bar_fixed.mp4

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards.
  • I've completed the PR template to the best of my ability
  • I've included tests if applicable — existing TabsBar unit tests pass (55/55); no new tests required for layout measurement edge case
  • I've documented my code using JSDoc format if applicable — N/A (inline helpers are self-explanatory)
  • I've applied the right labels on the PR (see labeling guidelines). Not required for external contributors.

Performance checks (if applicable)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces for production performance metrics

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Low Risk
Localized TabsBar layout/animation logic with no auth, data, or API impact; behavior change is limited to tab underline positioning and scroll detection timing.

Overview
Fixes the TabsBar animated underline staying on the wrong tab when the tab list changes (e.g. conditional Activity tabs appearing after a network filter change).

Layout state now uses dense arrays (Array.from + undefined slots) and a strict areAllTabLayoutsMeasured helper so sparse-array holes cannot make readiness checks pass early. On structural tab changes, layoutGeneration is bumped and included in each Tab key to remount tabs and re-fire onLayout, replacing the old container-width reset trick.

handleTabLayout repositions the underline via requestAnimationFrame as soon as the active tab has valid measurements, and activeIndex animation only runs when all layouts are truly measured.

Reviewed by Cursor Bugbot for commit cb4c130. Bugbot is set up for automated code reviews on this repo. Configure here.

Fixes incorrect underline position on Activity when conditional tabs
(e.g. Perps) mount/unmount after network filter changes.

Fixes #30365
Relates-to: TMCU-755
@wachunei wachunei requested a review from a team as a code owner May 26, 2026 14:57
@github-actions github-actions Bot added pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. size-S labels May 26, 2026
@wachunei wachunei added team-design-system All issues relating to design system in Mobile team-mobile-ux Mobile UX team and removed pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. labels May 26, 2026
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.33333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.31%. Comparing base (9227392) to head (95008f0).
⚠️ Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
...t-library/components-temp/Tabs/TabsBar/TabsBar.tsx 93.33% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #30640      +/-   ##
==========================================
+ Coverage   82.28%   82.31%   +0.03%     
==========================================
  Files        5525     5539      +14     
  Lines      148957   149153     +196     
  Branches    34320    34355      +35     
==========================================
+ Hits       122568   122781     +213     
+ Misses      18033    18012      -21     
- Partials     8356     8360       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wachunei
Copy link
Copy Markdown
Member Author

cursor review

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 95008f0. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeWalletPlatform, SmokePredictions, SmokePerps, SmokeMoney
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 82%
click to see 🤖 AI reasoning details

E2E Test Selection:
The change is to TabsBar.tsx, a shared animated tab bar component used across multiple key views:

  1. SmokeWalletPlatform: The TabsList (which wraps TabsBar) is used in the main Wallet view for Tokens/NFTs/Activity tabs, and in TrendingView for the Trending/Explore tabs. Any regression in tab layout measurement or animation could break tab navigation in the wallet home screen.

  2. SmokePredictions: PredictFeed.tsx and PredictMarketDetailsTabBar.tsx use TabsBar directly. The fix to layout measurement and underline animation directly affects how prediction market tabs render and animate.

  3. SmokePerps: Perps is a section inside the Trending tab (which uses TabsList/TabsBar). Tab navigation changes could affect how users navigate to the Perps section.

  4. SmokeMoney: HomepageDiscoveryTabs uses TabsList with TabsBar for homepage discovery tabs, which is part of the wallet home screen experience.

The changes fix: sparse array layout measurement bugs, tab remounting strategy (using layoutGeneration key instead of container width reset), early underline positioning, and improved areAllTabLayoutsMeasured validation. These are behavioral changes to animation and layout logic that could have visual regressions in tab switching, underline animation, and overflow detection across all consuming views.

SmokeConfirmations, SmokeAccounts, SmokeSwap, SmokeStake, SmokeNetworkExpansion, SmokeNetworkAbstractions, SmokeMultiChainAPI, SmokeBrowser, SmokeSnaps, SmokeIdentity, SmokeSeedlessOnboarding are not directly affected as they don't primarily rely on the TabsBar component for their core flows.

Performance Test Selection:
The TabsBar change is a bug fix for layout measurement and animation logic (fixing sparse array issues, improving remounting strategy). While it touches animation code, it doesn't introduce new rendering overhead or change data loading patterns. The fix is correctness-oriented rather than performance-impacting. No performance test tags are warranted.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
3.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@wachunei wachunei added the skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. label May 26, 2026
Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

Tested on iPhone 15 Pro simulator

To trigger the tab add/remove scenario, temporarily modified isPerpsEnabled to toggle with the network filter (Popular networks = 4 tabs, single network = 3 tabs), which is the condition that drives the bug.

Underline tracking: pass

  • Removed Perps (4→3 tabs): underline correctly snapped to Transactions even though Perps (index 2) was the previously active tab
  • Re-added Perps (3→4 tabs): underline stayed on Transactions and correctly followed to Transfers on tap
  • No stuck underline observed in any transition

Overflow scroll detection: pass

  • Tab bar was scrollable in the 4-tab overflow state throughout, including after a 3→4 tab structural change

@wachunei wachunei enabled auto-merge May 26, 2026 19:43
@wachunei wachunei added this pull request to the merge queue May 26, 2026
Merged via the queue into main with commit 2099d4a May 26, 2026
271 of 274 checks passed
@wachunei wachunei deleted the fix/TMCU-755-activity-tab-underline-stuck-v2 branch May 26, 2026 20:02
@github-actions github-actions Bot locked and limited conversation to collaborators May 26, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.80.0 Issue or pull request that will be included in release 7.80.0 label May 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.80.0 Issue or pull request that will be included in release 7.80.0 size-S skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-design-system All issues relating to design system in Mobile team-mobile-ux Mobile UX team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Activity tab underline gets stuck

5 participants