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
{{ message }}
Repository navigation
Web/Safari - Account Settings - Confirmation buttons in RHP settings cut off in Safari #86276
Version Number: 9.3.42-0 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack: Exploratory when retest issue https://github.com/Expensify/Expensify/issues/432325 Email or phone of affected tester (no customers):fischer9966+053122@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Critical User Impact Device used: MacOS 26.3.1 / Safari App Component: User Settings
Action Performed:
Go to staging.new.expensify.com in Safari
Login with any account
Go to Account > Any Settings with confirmation buttons eq. Profile > Display name, Contact methods. Profile > Security > Any menu point, etc
Verify that RHP with settings has confirmation buttons in the bottom
Expected Result:
RHP with settings has confirmation buttons in the bottom in Safari
Actual Result:
Bug 1:
Confirmation buttons in RHP settings cut off in Safari. Main window content is not displayed.
Bug 2:
A blank background gets displayed.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
PR #85887 should be reverted from staging. This was a CP (Cherry-Pick) to staging that is causing Safari-specific layout issues.
Labels: No label changes needed - this is correctly labeled as DeployBlockerCash (App/frontend issue)
Detailed Analysis
Evidence
PR #85887 was merged to staging on March 20, 2026 (label "CP Staging" confirms it is staging-only). The issue appeared after this date and is reproducible only on staging, not production, which perfectly matches the PR's deployment timeline.
Verification
The PR modified src/components/ScreenWrapper/ScreenWrapperContainer.tsx, adding Safari-specific viewport resize handling (lines 189-208 in current code):
useEffect(()=>{consthandleViewportResize=()=>{if(!isSafari()){return;}setIsBlurred(false);// This is the problematic line};constremoveResizeListener=addViewportResizeListener(handleViewportResize);return()=>{removeResizeListener();};},[setIsBlurred]);
Root Cause
When Safari resizes the viewport (which happens frequently in Safari), the handler sets isBlurred(false). This state controls whether maxHeight is applied to the KeyboardAvoidingView (line 230):
In Safari RHP settings pages, this maxHeight restriction is cutting off the bottom confirmation buttons because the content exceeds the calculated viewport height. The main window content becomes hidden, and buttons are not visible.
This is a Safari-specific bug because only Safari triggers the viewport resize handler that forces isBlurred to false, thereby always applying the height restriction.
Why This is a Frontend Bug
The fix requires reverting PR #85887 from staging (or finding an alternative fix in the App codebase). No backend changes are involved.
Please re-state the problem that we are trying to solve in this issue.
On Safari (MacOS), confirmation buttons (Save/Update) in RHP settings pages (Profile > Display Name, Contact Methods, Security, etc.) are cut off, main window content doesn't render properly, and a blank background appears. This is reproducible in staging (v9.3.42-0) but not in production, indicating a regression from a recently merged PR.
What is the root cause of that problem?
After analyzing all 42 PRs in the current staging release (comparing production to staging), the only PR that modified the shared form infrastructure used by the affected settings pages is PR #84516 ("fix: The displayed error messages are not announced once they appear").
This PR modified FormProvider.tsx, FormWrapper.tsx, FormContext.tsx, FormAlertWrapper.tsx, and FormHelpMessage.tsx — the exact component chain used by every RHP settings page with confirmation buttons (DisplayNamePage uses ScreenWrapper → FormProvider → FormWrapper → FormAlertWithSubmitButton).
New hidden <Text> elements with style={styles.hiddenElementOutsideOfWindow} (position: absolute, top: -10000) are inserted inside FormWrapper's FormElement (between form children and the submit button) and inside FormHelpMessage
New state and context values added to FormProvider (errorAnnouncementKey, getErrorAnnouncementKey, getFallbackAnnouncementMessage) causing additional re-render cycles
FormAlertWrapper now always passes a non-empty announcementMessage to FormHelpMessage (previously passed empty string when no message existed)
Safari has documented quirks with position: absolute elements inside flex/scroll containers, and the RHP settings layout already has Safari-specific handling (ScreenWrapperContainer.tsx:230 removes maxHeight when isBlurred is true on Safari, useRHPScreenOptions.ts:47-49 applies a custom card style interpolator with overflow: hidden for Safari). The combination of the new hidden elements and additional re-renders from PR #84516 likely triggers a Safari-specific layout calculation issue in the deeply nested flex hierarchy: position:fixed card → KeyboardAvoidingView(w100, h100, maxHeight) → PickerAvoidingView(flex:1) → ScrollView(flex:1, flexGrow:1) → FormElement → [children + hidden Text + SubmitButton].
Important note: The core Safari layout infrastructure (ScreenWrapperContainer, browser detection, viewport handling, card styles) is completely unchanged between production and staging. The regression comes from how PR #84516's form changes interact with Safari's rendering engine in this pre-existing layout hierarchy.
What changes do you think we should make in order to solve the problem?
Option A (Recommended — targeted fix): In FormWrapper.tsx, move the hidden announcement <Text> elements outside of the FormElement/ScrollView container so they don't participate in the flex layout calculation. Specifically, render them as siblings of the ScrollView within the outer View(flex:1) wrapper, or use a React Portal to render them outside the form hierarchy entirely.
Option B (Quick verification): Revert PR #84516 on staging to confirm it's the cause, then re-land with the fix from Option A applied.
The relevant files to modify:
src/components/Form/FormWrapper.tsx — move hidden <Text> elements out of FormElement
src/components/FormHelpMessage.tsx — similarly move hidden <Text> out of the form content flow
What alternative solutions did you explore? (Optional)
Navigation changes (PR Preserve deep-linked report route during onboarding guard redirect #85556): Investigated the RootStackRouter.ts redirect handling changes, but these only execute during navigation guard REDIRECT events (onboarding/migration modals) and wouldn't affect normal settings navigation for authenticated users.
Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot to refine this analysis, or explain why you are rejecting Melvin's proposal.
@MelvinBot are you sure #84516 is the cause? I can’t reproduce this on staging or main. The PR also isn't deployed to staging yet. Am I missing something?
The staging deploy checklist also lists it as checked. So the PR is in staging but not production, which matches the timing of this regression.
Regarding not being able to reproduce: The hidden <Text> elements from your PR only render conditionally:
FormWrapper hidden Text: only when errorAnnouncementKey > 1 (after form submission with server error)
FormHelpMessage hidden Text: only when shouldReannounceOnSubmit && hasError && errorAnnouncementKey > 0
If you're testing just by loading the page without triggering form errors, the hidden elements wouldn't render, which could explain why you can't reproduce it. The issue may require:
Submitting a form with a validation error first (to trigger errorAnnouncementKey increment)
Being on a specific Safari version (the reporter used macOS 26.3.1 / Safari)
Interacting with the form inputs (to trigger the Safari isBlurred state in ScreenWrapperContainer.tsx:230)
However, the FormAlertWrapper change (always passing a non-empty announcementMessage instead of empty string) and the additional FormContext values (getErrorAnnouncementKey, getFallbackAnnouncementMessage) are active on every render, not just after errors. These could cause additional re-render cycles that interact with Safari's layout engine in the constrained maxHeight=windowHeight RHP container.
Suggested debugging steps:
Test on Safari specifically (the reporter used macOS Safari, not Chrome)
On the Display Name page, edit the name, trigger a validation error by clearing both fields and hitting Save, then try navigating
Check Safari DevTools for the computed height of the KeyboardAvoidingView and FormElement containers — are they overflowing the maxHeight constraint?
I still believe PR #84516 is the most likely cause since it's the only change between production and staging that touches the shared form infrastructure used by all affected pages. No other PR modified ScreenWrapper, ScreenWrapperContainer, navigation card styles, or the settings pages themselves.
Thanks for the feedback — that's a valid point. The hiddenElementOutsideOfWindow style is indeed already used in TextInputMeasurement (which renders on these same pages) without causing Safari layout issues, so the hidden <Text> elements alone are unlikely to be the root cause.
After broadening the investigation, here's an updated analysis:
Key Observation: macOS 26.3.1 / Safari 26
The reporter is on macOS 26.3.1 (Tahoe) which runs Safari 26 — a very new engine version. The codebase has extensive Safari-specific workarounds for position: fixed height calculation bugs (documented in issues #12005, #17824, #20709):
getNavigationModalCardStyles uses position: fixed instead of absolute specifically to work around Safari height issues (src/styles/utils/getNavigationModalCardStyles/index.ts:6-14)
ScreenWrapperContainer disables minHeight for Safari (src/components/ScreenWrapper/ScreenWrapperContainer.tsx:123)
RHP uses a custom cardStyleInterpolator on Safari with overflow: hidden (src/libs/Navigation/AppNavigator/useRHPScreenOptions.ts:47-49)
If you're testing on a different macOS/Safari version (e.g., macOS 15 / Safari 18), that could explain why you can't reproduce it. The regression may be Safari 26-specific.
Revised Candidate PRs
PR Preserve deep-linked report route during onboarding guard redirect #85556 ("Preserve deep-linked report route during onboarding guard redirect") — Strong candidate for the "blank background" symptom. It changes RootStackRouter.ts:97-118 to preserve existing fullscreen routes during navigation guard redirects instead of resetting the stack. If a guard redirect fires while in Settings, the stack could end up in an unexpected state with Settings partially rendered underneath.
PR fix: The displayed error messages are not announced once they appear. #84516 — Weakened but not fully ruled out. The hidden elements only render when errorAnnouncementKey > 0 (after form submission with errors). If the bug occurs on initial page load before any form interaction, this PR is not the cause.
Safari 26 engine changes — The existing position: fixed + overflow: hidden + disabled minHeight workarounds may behave differently in Safari 26's rendering engine.
Suggested Next Steps
Can someone reproduce on macOS 26.3.1 / Safari 26 specifically? The reporter's exact environment matters.
Activity
melvin-bot commentedon Mar 24, 2026
Triggered auto assignment to @youssef-lr (
DeployBlockerCash), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.melvin-bot commentedon Mar 24, 2026
💬 A slack conversation has been started in #expensify-open-source
github-actions commentedon Mar 24, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
OSBotify commentedon Mar 24, 2026
Investigation Summary
Classification: Frontend bug
Causing PR: #85887 - "Revert focus restoration mechanism" by @marcaaron (High confidence)
Related Issues: This PR was a revert of #79834 to fix issues #85866, #85874, #85878, #85886, #85896, #85895
Recommendation: REVERT
PR #85887 should be reverted from staging. This was a CP (Cherry-Pick) to staging that is causing Safari-specific layout issues.
Labels: No label changes needed - this is correctly labeled as DeployBlockerCash (App/frontend issue)
Detailed Analysis
Evidence
PR #85887 was merged to staging on March 20, 2026 (label "CP Staging" confirms it is staging-only). The issue appeared after this date and is reproducible only on staging, not production, which perfectly matches the PR's deployment timeline.
Verification
The PR modified
src/components/ScreenWrapper/ScreenWrapperContainer.tsx, adding Safari-specific viewport resize handling (lines 189-208 in current code):Root Cause
When Safari resizes the viewport (which happens frequently in Safari), the handler sets
isBlurred(false). This state controls whethermaxHeightis applied to the KeyboardAvoidingView (line 230):In Safari RHP settings pages, this
maxHeightrestriction is cutting off the bottom confirmation buttons because the content exceeds the calculated viewport height. The main window content becomes hidden, and buttons are not visible.This is a Safari-specific bug because only Safari triggers the viewport resize handler that forces
isBlurredto false, thereby always applying the height restriction.Why This is a Frontend Bug
The fix requires reverting PR #85887 from staging (or finding an alternative fix in the App codebase). No backend changes are involved.
MelvinBot commentedon Mar 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Safari (MacOS), confirmation buttons (Save/Update) in RHP settings pages (Profile > Display Name, Contact Methods, Security, etc.) are cut off, main window content doesn't render properly, and a blank background appears. This is reproducible in staging (v9.3.42-0) but not in production, indicating a regression from a recently merged PR.
What is the root cause of that problem?
After analyzing all 42 PRs in the current staging release (comparing production to staging), the only PR that modified the shared form infrastructure used by the affected settings pages is PR #84516 ("fix: The displayed error messages are not announced once they appear").
This PR modified
FormProvider.tsx,FormWrapper.tsx,FormContext.tsx,FormAlertWrapper.tsx, andFormHelpMessage.tsx— the exact component chain used by every RHP settings page with confirmation buttons (DisplayNamePage usesScreenWrapper→FormProvider→FormWrapper→FormAlertWithSubmitButton).Key changes from PR #84516:
<Text>elements withstyle={styles.hiddenElementOutsideOfWindow}(position: absolute, top: -10000) are inserted insideFormWrapper'sFormElement(between form children and the submit button) and insideFormHelpMessageFormProvider(errorAnnouncementKey,getErrorAnnouncementKey,getFallbackAnnouncementMessage) causing additional re-render cyclesFormAlertWrappernow always passes a non-emptyannouncementMessagetoFormHelpMessage(previously passed empty string when no message existed)Safari has documented quirks with
position: absoluteelements inside flex/scroll containers, and the RHP settings layout already has Safari-specific handling (ScreenWrapperContainer.tsx:230removesmaxHeightwhenisBlurredis true on Safari,useRHPScreenOptions.ts:47-49applies a custom card style interpolator withoverflow: hiddenfor Safari). The combination of the new hidden elements and additional re-renders from PR #84516 likely triggers a Safari-specific layout calculation issue in the deeply nested flex hierarchy:position:fixed card → KeyboardAvoidingView(w100, h100, maxHeight) → PickerAvoidingView(flex:1) → ScrollView(flex:1, flexGrow:1) → FormElement → [children + hidden Text + SubmitButton].Important note: The core Safari layout infrastructure (ScreenWrapperContainer, browser detection, viewport handling, card styles) is completely unchanged between production and staging. The regression comes from how PR #84516's form changes interact with Safari's rendering engine in this pre-existing layout hierarchy.
What changes do you think we should make in order to solve the problem?
Option A (Recommended — targeted fix): In
FormWrapper.tsx, move the hidden announcement<Text>elements outside of theFormElement/ScrollViewcontainer so they don't participate in the flex layout calculation. Specifically, render them as siblings of theScrollViewwithin the outerView(flex:1)wrapper, or use a React Portal to render them outside the form hierarchy entirely.Option B (Quick verification): Revert PR #84516 on staging to confirm it's the cause, then re-land with the fix from Option A applied.
The relevant files to modify:
src/components/Form/FormWrapper.tsx— move hidden<Text>elements out ofFormElementsrc/components/FormHelpMessage.tsx— similarly move hidden<Text>out of the form content flowWhat alternative solutions did you explore? (Optional)
RootStackRouter.tsredirect handling changes, but these only execute during navigation guard REDIRECT events (onboarding/migration modals) and wouldn't affect normal settings navigation for authenticated users.SelectionListmigration #84880): A 135-file refactor, but it only affects list-based components — the affected settings pages useFormProvider/FormWrapper, notSelectionList.Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot to refine this analysis, or explain why you are rejecting Melvin's proposal.
youssef-lr commentedon Mar 24, 2026
Checking
youssef-lr commentedon Mar 25, 2026
@Krishna2323 can you take a look please? this seems related to your PR
1 remaining item
Krishna2323 commentedon Mar 25, 2026
@MelvinBot are you sure #84516 is the cause? I can’t reproduce this on staging or main. The PR also isn't deployed to staging yet. Am I missing something?
MelvinBot commentedon Mar 25, 2026
Thanks for the feedback! I double-checked, and PR #84516 is deployed to staging. Here's the verification:
The staging deploy checklist also lists it as checked. So the PR is in staging but not production, which matches the timing of this regression.
Regarding not being able to reproduce: The hidden
<Text>elements from your PR only render conditionally:FormWrapperhidden Text: only whenerrorAnnouncementKey > 1(after form submission with server error)FormHelpMessagehidden Text: only whenshouldReannounceOnSubmit && hasError && errorAnnouncementKey > 0If you're testing just by loading the page without triggering form errors, the hidden elements wouldn't render, which could explain why you can't reproduce it. The issue may require:
isBlurredstate inScreenWrapperContainer.tsx:230)However, the
FormAlertWrapperchange (always passing a non-emptyannouncementMessageinstead of empty string) and the additionalFormContextvalues (getErrorAnnouncementKey,getFallbackAnnouncementMessage) are active on every render, not just after errors. These could cause additional re-render cycles that interact with Safari's layout engine in the constrainedmaxHeight=windowHeightRHP container.Suggested debugging steps:
KeyboardAvoidingViewandFormElementcontainers — are they overflowing themaxHeightconstraint?I still believe PR #84516 is the most likely cause since it's the only change between production and staging that touches the shared form infrastructure used by all affected pages. No other PR modified
ScreenWrapper,ScreenWrapperContainer, navigation card styles, or the settings pages themselves.Krishna2323 commentedon Mar 25, 2026
@MelvinBot I still can't repro the issue. BTW the same style on View and test is used in
TextInputMeasurementcomponent.MelvinBot commentedon Mar 25, 2026
Thanks for the feedback — that's a valid point. The
hiddenElementOutsideOfWindowstyle is indeed already used inTextInputMeasurement(which renders on these same pages) without causing Safari layout issues, so the hidden<Text>elements alone are unlikely to be the root cause.After broadening the investigation, here's an updated analysis:
Key Observation: macOS 26.3.1 / Safari 26
The reporter is on macOS 26.3.1 (Tahoe) which runs Safari 26 — a very new engine version. The codebase has extensive Safari-specific workarounds for
position: fixedheight calculation bugs (documented in issues #12005, #17824, #20709):getNavigationModalCardStylesusesposition: fixedinstead ofabsolutespecifically to work around Safari height issues (src/styles/utils/getNavigationModalCardStyles/index.ts:6-14)ScreenWrapperContainerdisablesminHeightfor Safari (src/components/ScreenWrapper/ScreenWrapperContainer.tsx:123)cardStyleInterpolatoron Safari withoverflow: hidden(src/libs/Navigation/AppNavigator/useRHPScreenOptions.ts:47-49)If you're testing on a different macOS/Safari version (e.g., macOS 15 / Safari 18), that could explain why you can't reproduce it. The regression may be Safari 26-specific.
Revised Candidate PRs
PR Preserve deep-linked report route during onboarding guard redirect #85556 ("Preserve deep-linked report route during onboarding guard redirect") — Strong candidate for the "blank background" symptom. It changes
RootStackRouter.ts:97-118to preserve existing fullscreen routes during navigation guard redirects instead of resetting the stack. If a guard redirect fires while in Settings, the stack could end up in an unexpected state with Settings partially rendered underneath.PR fix: The displayed error messages are not announced once they appear. #84516 — Weakened but not fully ruled out. The hidden elements only render when
errorAnnouncementKey > 0(after form submission with errors). If the bug occurs on initial page load before any form interaction, this PR is not the cause.Safari 26 engine changes — The existing
position: fixed+overflow: hidden+ disabledminHeightworkarounds may behave differently in Safari 26's rendering engine.Suggested Next Steps
grgia commentedon Mar 25, 2026
I also cannot reproduce
melvin-bot commentedon Mar 30, 2026
@youssef-lr Huh... This is 4 days overdue. Who can take care of this?
melvin-bot commentedon Mar 30, 2026
@youssef-lr Huh... This is 4 days overdue. Who can take care of this?
melvin-bot commentedon Mar 30, 2026
@youssef-lr Eep! 4 days overdue now. Issues have feelings too...