Skip to content

fix(perps): render perps toast via portal to escape CSS transform containing block#43613

Open
michalconsensys wants to merge 1 commit into
mainfrom
fix/perps-close-all-toast-portal
Open

fix(perps): render perps toast via portal to escape CSS transform containing block#43613
michalconsensys wants to merge 1 commit into
mainfrom
fix/perps-close-all-toast-portal

Conversation

@michalconsensys

@michalconsensys michalconsensys commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

The Tabs component (ui/components/ui/tabs/tabs.tsx) applies the Tailwind class transform-gpu, which translates to transform: translateZ(0). Per CSS spec, any ancestor with a transform creates a new containing block for position: fixed descendants. This caused perps toasts rendered inside PerpsToastProvider (which sits inside the Tabs tree on the home screen perps tab) to be positioned relative to the Tabs container instead of the viewport — making them effectively invisible.

This only affected toasts triggered from the perps tab (home screen). All other perps toasts (close single position, cancel order, edit margin, etc.) are triggered from dedicated perps pages inside PerpsLayout, which is NOT a descendant of the Tabs component and therefore unaffected.

Fix: Render the perps toast via ReactDOM.createPortal() to document.body, escaping the CSS transform containing block. This follows the same portal pattern the Modal component already uses.

Changelog

CHANGELOG entry: Fixed perps close-all-positions toasts not appearing on the home screen perps tab

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2852

Manual testing steps

  1. Run the extension locally.
  2. Navigate to the home screen and switch to the Perps tab.
  3. Ensure you have open positions.
  4. Click the "Close all" button in the positions header.
  5. Confirm the close in the modal that appears.
  6. Verify that an in-progress toast ("Closing all positions") appears at the bottom of the viewport.
  7. After the operation completes, verify that a success toast ("All positions closed") or error toast appears.
Screen.Recording.2026-06-16.at.15.34.43.mov

Pre-merge author checklist

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.

… block

The Tabs component applies `transform-gpu` which creates a new CSS
containing block, causing `position: fixed` toasts inside
PerpsToastProvider to be positioned relative to the Tabs container
instead of the viewport. This made close-all-positions toasts invisible
on the home perps tab.

Render the toast via `ReactDOM.createPortal` to `document.body` so it
escapes any ancestor transforms, matching the pattern used by Modal.
@github-actions

Copy link
Copy Markdown
Contributor

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.

@mm-token-exchange-service mm-token-exchange-service Bot added the team-perps Perps team label Jun 16, 2026
@mm-token-exchange-service

Copy link
Copy Markdown

✨ Files requiring CODEOWNER review ✨

👨‍🔧 @MetaMask/perps (2 files, +39 -16)
  • 📁 ui/
    • 📁 components/
      • 📁 app/
        • 📁 perps/
          • 📁 perps-toast/
            • 📄 perps-toast-provider.test.tsx +19 -0
            • 📄 perps-toast-provider.tsx +20 -16

@michalconsensys michalconsensys marked this pull request as ready for review June 16, 2026 13:35
@michalconsensys michalconsensys requested a review from a team as a code owner June 16, 2026 13:35
@mm-token-exchange-service

Copy link
Copy Markdown
Builds ready [a057d66]
Deprecated Browserify fallback builds
⚡ Performance Benchmarks (Total: 🟢 15 pass · 🟡 10 warn · 🔴 0 fail)

Baseline (latest main): dd70ee8 | Date: 6/16/2026 | Pipeline: 27621378511 | Baseline logs

Interaction Benchmarks · Samples: 5
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
confirmTx
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
🟡 bridge_search_token

📈 Results compared to the previous 5 runs on main

  • loadNewAccount/load_new_account: -11%
  • loadNewAccount/total: -11%
  • loadNewAccount/inp: +42%
  • bridgeUserActions/bridge_load_page: +11%
  • bridgeUserActions/longTaskCount: +100%
  • bridgeUserActions/longTaskTotalDuration: +48%
  • bridgeUserActions/tbt: +17%
  • bridgeUserActions/inp: -21%
  • bridgeUserActions/lcp: +938%
  • loadNewAccount/load_new_account: +33%
  • loadNewAccount/total: +33%
  • loadNewAccount/inp: -15%
  • loadNewAccount/fcp: -47%
  • loadNewAccount/lcp: +1388%
  • confirmTx/confirm_tx: +11%
  • confirmTx/longTaskCount: -100%
  • confirmTx/longTaskTotalDuration: -100%
  • confirmTx/longTaskMaxDuration: -100%
  • confirmTx/tbt: -100%
  • confirmTx/total: +11%
  • confirmTx/inp: -15%
  • confirmTx/fcp: -47%
  • confirmTx/lcp: +1171%
  • bridgeUserActions/bridge_load_page: +44%
  • bridgeUserActions/bridge_load_asset_picker: +53%
  • bridgeUserActions/bridge_search_token: +201%
  • bridgeUserActions/longTaskCount: -100%
  • bridgeUserActions/longTaskTotalDuration: -100%
  • bridgeUserActions/longTaskMaxDuration: -100%
  • bridgeUserActions/tbt: -100%
  • bridgeUserActions/total: +172%
  • bridgeUserActions/inp: -21%
  • bridgeUserActions/fcp: -46%
  • bridgeUserActions/lcp: +1217%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 loadNewAccount/LCP: p75 2.6s
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
startupPowerUserHome
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]

📈 Results compared to the previous 5 runs on main

  • startupStandardHome/cls: -100%
  • startupPowerUserHome/numNetworkReqs: -12%
  • startupStandardHome/initialActions: +11%
  • startupStandardHome/inp: -29%
  • startupPowerUserHome/backgroundConnect: -17%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🔴 startupPowerUserHome/INP: p75 544ms
  • 🟡 startupPowerUserHome/LCP: p75 3.2s
User Journey Benchmarks · Samples: 5 · mock API
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total
assetDetails
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]
solanaAssetDetails
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
importSrpHome
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
sendTransactions
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]
swap
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • onboardingImportWallet/doneButtonToHomeScreen: -88%
  • onboardingImportWallet/openAccountMenuToAccountListLoaded: -98%
  • onboardingImportWallet/longTaskCount: -77%
  • onboardingImportWallet/longTaskTotalDuration: -91%
  • onboardingImportWallet/longTaskMaxDuration: -89%
  • onboardingImportWallet/tbt: -96%
  • onboardingImportWallet/total: -87%
  • onboardingNewWallet/skipBackupToMetricsScreen: +13%
  • onboardingNewWallet/doneButtonToAssetList: -32%
  • onboardingNewWallet/longTaskTotalDuration: -20%
  • onboardingNewWallet/longTaskMaxDuration: -16%
  • onboardingNewWallet/tbt: -44%
  • onboardingNewWallet/total: -27%
  • solanaAssetDetails/assetClickToPriceChart: -65%
  • solanaAssetDetails/longTaskCount: -100%
  • solanaAssetDetails/longTaskTotalDuration: -100%
  • solanaAssetDetails/longTaskMaxDuration: -100%
  • solanaAssetDetails/tbt: -100%
  • solanaAssetDetails/total: -65%
  • solanaAssetDetails/inp: -19%
  • solanaAssetDetails/cls: -91%
  • importSrpHome/homeAfterImportWithNewWallet: -38%
  • importSrpHome/longTaskCount: -25%
  • importSrpHome/longTaskTotalDuration: -37%
  • importSrpHome/longTaskMaxDuration: -11%
  • importSrpHome/tbt: -36%
  • importSrpHome/total: -33%
  • importSrpHome/inp: -20%
  • sendTransactions/openSendPageFromHome: +67%
  • sendTransactions/selectTokenToSendFormLoaded: -53%
  • sendTransactions/reviewTransactionToConfirmationPage: -13%
  • sendTransactions/tbt: +14%
  • sendTransactions/total: -12%
  • sendTransactions/inp: -13%
  • sendTransactions/cls: -78%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 assetDetails/FCP: p75 1.9s
  • 🟡 sendTransactions/INP: p75 216ms
  • 🟡 assetDetails/FCP: p75 1.9s
  • 🟡 solanaAssetDetails/FCP: p75 1.9s
  • 🟡 importSrpHome/FCP: p75 1.8s
  • 🟡 sendTransactions/FCP: p75 1.9s
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]
Bundle size diffs
  • background: 58 Bytes (0%)
  • ui: 111 Bytes (0%)
  • common: 20 Bytes (0%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants