Repository navigation
Fix multiline EditableText selection highlighting width - #185239
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the EditableText widget to use a new helper method, _selectionWidthStyleForMaxLines, which defaults the selection width style to BoxWidthStyle.tight for multiline text. New tests verify this behavior and ensure that explicit styles are still honored. Review feedback suggests adding documentation to the new private helper method to comply with the Flutter style guide and recommends updating the selectionHeightStyle initialization for consistency.
|
Addressed, thanks.
|
| } | ||
| // Multi-line selections should not be extended to match other lines' | ||
| // widths by default. | ||
| return ui.BoxWidthStyle.tight; |
There was a problem hiding this comment.
I think the default should always be to return tight for now, at least until we can figure out a reasonable behavior for max. I originally set this to max in #167762 because on native platforms with multi-line text fields, when moving onto the next line the highlight expands to cover the full width of the longest line.
I don't think tight vs max in single line should have any difference.
There was a problem hiding this comment.
Hi Renzo, made the suggested changes. now defaultSelectionWidthStyle always returns BoxWidthStyle.tight
There was a problem hiding this comment.
Thank you for the changes @anazr9!
So i've been thinking on this a little more. The selection behavior that I was trying to accomplish with max was to extend the highlight to the end of the input field similar to native platforms. BoxWidthStyle alone will not be enough to do this since max will only extend the highlight to the width of the longest line.
Our options here are:
- Switch to
tightlike we are now. File an issue for the native selection behavior that extends the highlight to the width of the input field. - Keep the existing default, and fix the issue in
_TextHighlightPainterlocated ineditable.dart. Essentially split the selection highlight into two calls togetBoxesForSelection, where the last line in the selection has a width style oftight. File an issue for the native selection behavior that extends the highlight to the width of the input field.
I'm on the fence a little since neither change gets us to native parity but both fix the issue. Option 1 fixes the issue by changing the behavior of a public API EditableText.defaultSelectionWidthStyle. tight does not match the native behavior. Option 2 fixes the issue in a more private way by targeting the _TextHighlightPainter. Keeping the default max here also does not match native as the longest line width is not the same as input field width.
If we do implement the native behavior, what does that mean for the users that set selectionWidthStyle. What do they expect? The documentation of BoxWidthStyle.max would not match up with the behavior of extending the highlight to the width of the input field.
Right now I want to see if this change passes google testing as is. If it does that will be a good signal to whether this is a safe change to make. If there are considerable test failures then I think we should explore a solution where we keep the existing default.
There was a problem hiding this comment.
Below is how option 2 would look.
Screen.Recording.2026-04-30.at.8.23.40.PM.mov
The video below is the selection behavior on macOS with a SwiftUI application.
Screen.Recording.2026-04-30.at.8.25.44.PM.mov
There was a problem hiding this comment.
Hi @Renzo-Olivares, thanks for sharing your thoughts. I believe we should proceed with Option 1 and then we can create a separate issue to work on handling the native selection behavior that extends the highlight to the width of the input field.
Regarding the documentation and behavior of BoxWidthStyle.max, I think that instead of matching the width of the input (as shown in your first recording), it would be better to align with the native platform behavior—highlighting the entire available input field (as demonstrated in your second recording), if feasible.
At this point, the changes in this PR appear to have passed Google testing, so this is a safe change.
There was a problem hiding this comment.
I agree option 1 is the safer route and gets the fix out quicker. I'm not confident enough that a two pass paint for the selection would not run into edge cases with RTL and bidi text.
|
Hi @anazr9, thank you for your contribution! This is definitely an issue we want to fix. I left a comment about the approach, I think we could simplify it by always returning |
|
hi @Renzo-Olivares thanks for the review, I have made the changes based on your feedback and pushed the updated code. |
Renzo-Olivares
left a comment
There was a problem hiding this comment.
Thank you for the changes @anazr9, followed up in #185239 (comment)
|
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
| return ui.BoxWidthStyle.tight; | ||
| } | ||
| return ui.BoxWidthStyle.max; | ||
| return ui.BoxWidthStyle.tight; |
There was a problem hiding this comment.
Let's also change the default selectionWidthStyle in RenderEditable back to tight. That would resolve #180311 as well.
There was a problem hiding this comment.
I have changed the selectionWidthStyle in RenderEditable to tight
| skip: kIsWeb, // [intended] | ||
| ); | ||
|
|
||
| testWidgets('EditableText uses tight selection width style by default', ( |
There was a problem hiding this comment.
I suggest we use a scuba for this test similar to 'default text selection height style' test in this file.
There was a problem hiding this comment.
I have updated the test case to match similar to default text selection height style test
|
hi Renzo-Olivares , I have made the suggested changes, please review. Thanks ! |
| ); | ||
|
|
||
| await tester.pumpWidget( | ||
| MaterialApp( |
There was a problem hiding this comment.
nit: MaterialApp -> TestWidgetsApp. In general we should not import or continue to use Material components in widgets library tests.
There was a problem hiding this comment.
Oh okay, I have changed it from MaterialApp to TestWidgetsApp.
| ); | ||
| }, variant: TargetPlatformVariant.all()); | ||
|
|
||
| testWidgets('Explicit selectionWidthStyle is honored for multiline EditableText', ( |
There was a problem hiding this comment.
I think for this test, we should have some multi-line text (two lines is sufficient), where the last line is longer than the first, and select the last character of the first line. We should verify that the selection highlight in this scenario does not expand to the width of the second line. We can also do this with a golden test though it may be worth checking if there is a way to programmatically test this by verifying the selection rect painted by RenderEditable.
There was a problem hiding this comment.
Updated, thanks. I changed the test to cover the specific multiline case:
- First line is shorter than the second line
- only the last character of the first line is selected
- the test asserts the painted selection rect stays tight to that character and does not expand to the longer second line width.
I made this a programmatic paint assertion so it directly verifies the RenderEditable selection rect behaviour.
Renzo-Olivares
left a comment
There was a problem hiding this comment.
@anazr9 thank you for your patience. Left a few comments about the tests otherwise changes are looking good.
|
Hi @Renzo-Olivares thanks for the review, I have gone through your comments and made the suggested changes for the test file. |
…er_detection_io.dart and _web_browser_detection_web.dart
Description
This PR fixes multiline text selection highlighting that can incorrectly include trailing whitespace width from another line.

In
EditableText, the defaultdefaultSelectionWidthStylenow returnsBoxWidthStyle.tightalwaysThis prevents multiline selections from being visually extended to match other line widths (the behavior reported in the issue), while preserving current single-line behavior and honoring explicit
selectionWidthStyleoverrides.Fixed issue
Fixes #174689
Fixes #180311
Tests
Added widget tests in
packages/flutter/test/widgets/editable_text_test.dart:EditableText uses tight selection width style by default for multilineExplicit selectionWidthStyle is honored for multiline EditableTextLocally verified:
flutter test packages/flutter/test/widgets/editable_text_test.dart --plain-name "selection width style"flutter test packages/flutter/test/material/text_field_test.dart --plain-name "text selection style"flutter analyze packages/flutter/lib/src/widgets/editable_text.dart packages/flutter/test/widgets/editable_text_test.dart