Skip to content

fix(perps): prevent keyboard rendering off-viewport on TP/SL and order entry screens cp-7.80.0#30843

Merged
michalconsensys merged 5 commits into
mainfrom
fix/perps-keyboard-off-viewport
Jun 2, 2026
Merged

fix(perps): prevent keyboard rendering off-viewport on TP/SL and order entry screens cp-7.80.0#30843
michalconsensys merged 5 commits into
mainfrom
fix/perps-keyboard-off-viewport

Conversation

@michalconsensys

@michalconsensys michalconsensys commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Description

The keyboard renders off-page (outside the viewport) when a user interacts with input fields on certain Perps screens.

Root cause: The PerpsTPSLView (Take Profit / Stop Loss screen) uses TextInput components with showSoftInputOnFocus={false}, but this prop is Android-only. On iOS, tapping these TextInput fields still triggers the native keyboard, which stacks on top of the custom on-screen keypad and pushes content outside the viewport. The view has no KeyboardAvoidingView to handle this double-keyboard scenario.

Fix:

  • Dismiss the native keyboard on iOS via Keyboard.dismiss() inside a useEffect that fires when a TextInput receives focus. A isProgrammaticDismissRef guard prevents the resulting onBlur from hiding the custom keypad.
  • Switch PerpsOrderView's ScrollView to a compact content style (flexGrow: 0, paddingBottom: 0) when the custom keypad is active. The original style reserves 120px bottom padding for the absolutely-positioned "Place Order" button, which is hidden while the keypad is shown — this wasted vertical space could push the keypad off-viewport on smaller devices.

Changelog

CHANGELOG entry: Fixed keyboard rendering outside the viewport on Perps TP/SL and order entry screens on iOS

Related issues

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

Manual testing steps

Feature: Perps keyboard stays within viewport

  Scenario: user taps TP/SL input on iOS
    Given the wallet is unlocked and the user is on the Perps order entry screen

    When user taps the TP/SL row and taps a Take Profit or Stop Loss price input
    Then the custom keypad appears at the bottom of the screen
    And the native iOS keyboard does not appear
    And all content remains visible within the viewport

  Scenario: user taps amount input on a small-screen device
    Given the wallet is unlocked and the user is on the Perps order entry screen

    When user taps the amount display to open the custom keypad
    Then the keypad renders fully within the viewport
    And no input fields are obscured or inaccessible

Screenshots/Recordings

Before

IMG_8894

After

simulator_screenshot_501D11CD-176F-432A-80FE-A1CDB555DB20

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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
UI-only layout and keyboard handling on Perps order/TP-SL screens with no auth, payment, or trading logic changes.

Overview
Fixes iOS Perps screens where the native keyboard could stack on the custom keypad and push UI off-screen, because showSoftInputOnFocus={false} does not apply on iOS.

On PerpsTPSLView, focusing TP/SL TextInputs now calls Keyboard.dismiss() (via requestAnimationFrame) while a short-lived isProgrammaticDismissRef ignores the resulting onBlur so the custom keypad stays open; per-field blur handlers skip hook blur during that window. Focus/blur tests advance fake timers to clear the guard.

On PerpsOrderView, when the amount keypad is active the ScrollView uses scrollViewContentKeypad (flexGrow: 0, no bottom padding) instead of the style that reserves space for the hidden Place Order bar.

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

showSoftInputOnFocus is Android-only so on iOS the native keyboard
still appeared when TP/SL TextInputs were focused, stacking on top of
the custom keypad and pushing content outside the viewport.

Dismiss the native keyboard on iOS after focus and guard the onBlur
handler so the programmatic dismiss does not hide the custom keypad.

Also switch PerpsOrderView to a compact scroll-content style when the
keypad is active, dropping the 120px bottom padding reserved for the
Place Order button that is hidden in that state.
@github-actions

github-actions Bot commented Jun 1, 2026

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.

@metamaskbotv2 metamaskbotv2 Bot added the team-perps Perps team label Jun 1, 2026
@github-actions github-actions Bot added the size-S label Jun 1, 2026
@michalconsensys michalconsensys marked this pull request as ready for review June 1, 2026 10:45
@michalconsensys michalconsensys requested a review from a team as a code owner June 1, 2026 10:45
@github-actions github-actions Bot added the risk:medium AI analysis: medium risk label Jun 1, 2026
@michalconsensys michalconsensys changed the title fix(perps): prevent keyboard rendering off-viewport on TP/SL and order entry screens fix(perps): prevent keyboard rendering off-viewport on TP/SL and order entry screens cp-7.80.0 Jun 1, 2026
Comment thread app/components/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.tsx Outdated
Comment thread app/components/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.tsx
…rd dismiss

The useEffect cleanup only cancelled requestAnimationFrame but never
cleared the inner setTimeout, causing a race condition when switching
inputs quickly on iOS. Additionally, specific blur handlers (e.g.
handleTakeProfitPriceBlur) ran unconditionally before handleInputBlur,
bypassing the isProgrammaticDismissRef guard and resetting focus state
during programmatic keyboard dismissal.
Comment thread app/components/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.tsx Outdated
Advance fake timers between focus and blur events so the
isProgrammaticDismissRef resets to false before the blur fires,
matching the real-world sequence where a genuine user blur arrives
after the keyboard dismiss cycle completes.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d0e1509. Configure here.

Comment thread app/components/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.test.tsx Outdated
The keyboard dismiss logic lived in a useEffect keyed on focusedInput.
When the same input was re-focused, React deduplicated the state update
and the effect never re-fired, causing the native keyboard to reappear
alongside the custom keypad. Moving the dismiss into the callback
ensures it fires on every focus event.

Also wraps the fake-timer test body in try/finally so
jest.useRealTimers() always runs even if assertions throw.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.70588% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.66%. Comparing base (3a51914) to head (d56feef).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
...nts/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.tsx 62.50% 0 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #30843      +/-   ##
==========================================
- Coverage   82.77%   82.66%   -0.11%     
==========================================
  Files        5551     5551              
  Lines      142509   142784     +275     
  Branches    32882    32962      +80     
==========================================
+ Hits       117958   118030      +72     
- Misses      16699    16885     +186     
- Partials     7852     7869      +17     

☔ 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.

@gambinish gambinish added the skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. label Jun 1, 2026
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePerps, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: @PerformancePreps
  • Risk Level: medium
  • AI Confidence: 90%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes are contained to the Perps feature area:

  1. PerpsOrderView.styles.ts: Adds a new scrollViewContentKeypad style (flexGrow: 0, no padding) used when the custom keypad is active, preventing content overflow.

  2. PerpsOrderView.tsx: Conditionally applies the new scrollViewContentKeypad style when isInputFocused is true, fixing layout when the custom keypad is shown.

  3. PerpsTPSLView.tsx: iOS-specific fix adding a isProgrammaticDismissRef guard to prevent the custom keypad from disappearing when the native iOS keyboard is programmatically dismissed on focus. Uses requestAnimationFrame + 150ms setTimeout to reset the guard after the dismiss completes.

  4. PerpsTPSLView.test.tsx: Updates unit tests to use fake timers to properly handle the new async iOS keyboard dismiss guard.

These are UI/UX fixes for keyboard/keypad behavior in Perps order and TP/SL views. The changes are self-contained within the Perps component area.

Tag selection:

  • SmokePerps: Directly affected - PerpsOrderView and PerpsTPSLView are core Perps components
  • SmokeWalletPlatform: Required per SmokePerps tag description (Perps is a section inside the Trending tab)
  • SmokeConfirmations: Required per SmokePerps tag description (Add Funds deposits are on-chain transactions)

No other tags are warranted as the changes don't touch navigation, accounts, networks, browser, snaps, or other wallet features.

Performance Test Selection:
The PerpsOrderView style change introduces conditional flexGrow behavior (flexGrow: 0 vs default) based on input focus state, which could affect scroll view rendering performance in the Perps order flow. The @PerformancePreps tag covers perps market loading, position management, add funds flow, and order execution - directly relevant to the changed components.

View GitHub Actions results

@michalconsensys michalconsensys enabled auto-merge June 2, 2026 06:55
@michalconsensys michalconsensys added this pull request to the merge queue Jun 2, 2026
Merged via the queue into main with commit 2fc7adc Jun 2, 2026
434 of 446 checks passed
@michalconsensys michalconsensys deleted the fix/perps-keyboard-off-viewport branch June 2, 2026 07:22
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

risk:medium AI analysis: medium risk size-S skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants