Skip to content

Fix web PaymentElement scrolling in constrained layouts#2423

Open
khoadng wants to merge 3 commits into
flutter-stripe:mainfrom
khoadng:fix/payment-sheet-web-scrolling
Open

Fix web PaymentElement scrolling in constrained layouts#2423
khoadng wants to merge 3 commits into
flutter-stripe:mainfrom
khoadng:fix/payment-sheet-web-scrolling

Conversation

@khoadng

@khoadng khoadng commented Jun 4, 2026

Copy link
Copy Markdown

Fixes PaymentElement on web when it is placed inside a constrained layout. Fix #2045

Add an optional maxHeight. If Stripe reports content taller than that, the host div is capped and scrolls instead of growing past its parent.

Also adds the missing web stub for setConfirmHandler to make the package compile.

I tested the changes on our project, it is running on the old Flutter version (3.32.8), haven't verify on stable Flutter yet.


  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Do all checks pass?
  • Have you developed the feature on the latest stable version of Flutter?

  • AI was used to generate or assist with generating this PR. Please specify below how you used AI to help you, and what steps you have taken to manually verify the changes.

AI was used to help inspect the existing web implementation and draft the change. I manually reviewed the changes, tested the patched package in a Flutter web app using a constrained payment sheet, and ran package-level analysis/tests locally.


Summary by CodeRabbit

  • New Features

    • Payment elements now support maximum height constraints via a new maxHeight parameter.
  • Improvements

    • Refined web payment element height measurement and sizing behavior to reduce layout flicker and keep sizing stable under constraints.
  • Compatibility

    • The confirm-handler hook is not supported on web; attempts to use it will now fail explicitly.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5cd69906-7a63-405e-b2d4-05a857f9b370

📥 Commits

Reviewing files that changed from the base of the PR and between a510606 and 595fa2c.

📒 Files selected for processing (1)
  • packages/stripe_web/lib/src/web_stripe.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/stripe_web/lib/src/web_stripe.dart

📝 Walkthrough

Walkthrough

This PR blocks setConfirmHandler on WebStripe and adds maxHeight-based sizing to PaymentElement. The widget now tracks measured Stripe content height separately from the applied host height and updates sizing when height inputs change.

Changes

Web Platform Improvements

Layer / File(s) Summary
WebStripe confirm handler override
packages/stripe_web/lib/src/web_stripe.dart
setConfirmHandler now throws WebUnsupportedError.method('setConfirmHandler') on web.
PaymentElement height capping and measurement system
packages/stripe_web/lib/src/widgets/payment_element.dart
PaymentElement adds maxHeight, validates it, splits height tracking into measured and effective values, updates ResizeObserver and host CSS application, and recomputes sizing when height or maxHeight changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • remonh87

Poem

🐰 I nibbled on heights, then capped them neat,
The card now scrolls with a gentler beat.
No wobble, no bounce, just smooth little hops,
Web Stripe stays tidy from bottom to top.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing web PaymentElement scrolling in constrained layouts.
Linked Issues check ✅ Passed The changes address #2045 by capping PaymentElement height so it scrolls inside constrained web layouts.
Out of Scope Changes check ✅ Passed The added web confirm-handler stub is mentioned in the PR objectives and supports the main web fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@khoadng khoadng mentioned this pull request Jun 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/stripe_web/lib/src/widgets/payment_element.dart (2)

119-121: ⚡ Quick win

Remove redundant style assignments.

Lines 119-120 manually set height and minHeight, but line 121 immediately calls _applyHostHeight() which sets these same properties (along with maxHeight and overflow). The manual assignments are redundant.

♻️ Simplify by removing redundant assignments
     _divElement = web.HTMLDivElement()
       ..id = 'payment-element'
       ..style.border = 'none'
-      ..style.width = '100%'
-      ..style.height = '${_effectiveHeight}px'
-      ..style.minHeight = '${_effectiveHeight}px';
+      ..style.width = '100%';
     _applyHostHeight();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stripe_web/lib/src/widgets/payment_element.dart` around lines 119 -
121, Remove the redundant manual style assignments of height and minHeight that
use _effectiveHeight and rely on the existing _applyHostHeight() call to set
height, minHeight, maxHeight and overflow; specifically, in the PaymentElement
widget remove the two lines that set ..style.height = '${_effectiveHeight}px'
and ..style.minHeight = '${_effectiveHeight}px' so that only _applyHostHeight()
configures these properties (keep _effectiveHeight and _applyHostHeight()
as-is).

185-195: ⚡ Quick win

Consider allowing horizontal overflow when capped.

When the element is height-capped, line 193 sets overflowX = 'hidden', which prevents horizontal scrolling. If the PaymentElement contains wide form fields, labels, or validation messages that exceed the container width, they would be clipped without any way to view them.

Consider using overflowX = 'auto' to enable horizontal scrolling when needed, or omit setting it entirely to inherit the default behavior.

📜 Proposed change
     _divElement.style
       ..height = heightCss
       ..minHeight = heightCss
       ..maxHeight = _isHeightCapped ? heightCss : ''
-      ..overflowX = _isHeightCapped ? 'hidden' : ''
+      ..overflowX = ''
       ..overflowY = _isHeightCapped ? 'auto' : '';

Or if you want to enable horizontal scrolling when needed:

     _divElement.style
       ..height = heightCss
       ..minHeight = heightCss
       ..maxHeight = _isHeightCapped ? heightCss : ''
-      ..overflowX = _isHeightCapped ? 'hidden' : ''
+      ..overflowX = _isHeightCapped ? 'auto' : ''
       ..overflowY = _isHeightCapped ? 'auto' : '';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stripe_web/lib/src/widgets/payment_element.dart` around lines 185 -
195, In _applyHostHeight(), when _isHeightCapped is true the code sets
_divElement.style.overflowX = 'hidden' which can clip wide content; change that
assignment to 'auto' (or remove the overflowX assignment entirely) so horizontal
scrolling is allowed when needed; update the branch that references
_isHeightCapped in _applyHostHeight to use overflowX = 'auto' instead of
'hidden' to ensure wide form fields/labels remain accessible.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/stripe_web/lib/src/widgets/payment_element.dart`:
- Around line 119-121: Remove the redundant manual style assignments of height
and minHeight that use _effectiveHeight and rely on the existing
_applyHostHeight() call to set height, minHeight, maxHeight and overflow;
specifically, in the PaymentElement widget remove the two lines that set
..style.height = '${_effectiveHeight}px' and ..style.minHeight =
'${_effectiveHeight}px' so that only _applyHostHeight() configures these
properties (keep _effectiveHeight and _applyHostHeight() as-is).
- Around line 185-195: In _applyHostHeight(), when _isHeightCapped is true the
code sets _divElement.style.overflowX = 'hidden' which can clip wide content;
change that assignment to 'auto' (or remove the overflowX assignment entirely)
so horizontal scrolling is allowed when needed; update the branch that
references _isHeightCapped in _applyHostHeight to use overflowX = 'auto' instead
of 'hidden' to ensure wide form fields/labels remain accessible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4418c17-56cb-4370-bc44-01651db9d839

📥 Commits

Reviewing files that changed from the base of the PR and between 8b8d0eb and a510606.

📒 Files selected for processing (2)
  • packages/stripe_web/lib/src/web_stripe.dart
  • packages/stripe_web/lib/src/widgets/payment_element.dart

@remonh87 remonh87 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR I left a couple of remarks here

// layout height instead of Stripe's natural content height. Keep the
// previous natural measurement unless Stripe reports a larger height,
// otherwise the element can repeatedly cap and uncap while resizing.
if (!_isHeightCapped ||

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Once the content grows past maxHeight one time, this if only ever lets _measuredContentHeight go up never back down. So if the user switches to a shorter payment method (or some validation error happens) the element stays stuck at maxheight with a scrollbar even though the content would now fit. Best fix: measure stripeEl.scrollHeight instead of the contentRect.height. If you do this this guard can be removed entirely

_divElement.style.height = '${height}px';
});
final observedHeight = entry.contentRect.height.toDouble();
// Once the host is capped, ResizeObserver may report the capped

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also the guard below does not claim what the comment says. I would implement below suggestion and then we can get rid of it

..style.width = '100%'
..style.height = '${height}px'
..style.minHeight = '${height}px';
..style.height = '${_effectiveHeight}px'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think these assignments are not needed since we override them in _applyHostHeight

..height = heightCss
..minHeight = heightCss
..maxHeight = _isHeightCapped ? heightCss : ''
..overflowX = _isHeightCapped ? 'hidden' : ''

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am not sure about this oberflow we need to double check that some focus rings or dropdowns from the stripe element do not clip.

@remonh87 remonh87 added the Awaiting response Awaiting response from the issuer label Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Awaiting response Awaiting response from the issuer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Card is not scrolling

2 participants