Skip to content

Fix multiline EditableText selection highlighting width - #185239

Merged
auto-submit[bot] merged 29 commits into
flutter:masterfrom
anazr9:fix-174689-trailing-gap-selection
Oct 9, 2026
Merged

auto-submit[bot] merged 29 commits into
flutter:masterfrom
anazr9:fix-174689-trailing-gap-selection

Conversation

@anazr9

@anazr9 anazr9 commented Apr 18, 2026 •

Copy link
Copy Markdown
Contributor

Description

This PR fixes multiline text selection highlighting that can incorrectly include trailing whitespace width from another line.
Screenshot_1776501043

In EditableText, the default defaultSelectionWidthStyle now returns BoxWidthStyle.tight always

This 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 selectionWidthStyle overrides.

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 multiline
  • Explicit selectionWidthStyle is honored for multiline EditableText

Locally 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

@github-actions github-actions Bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. labels Apr 18, 2026

@gemini-code-assist gemini-code-assist 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.

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.

@anazr9

anazr9 commented Apr 18, 2026

Copy link
Copy Markdown
Contributor Author

Addressed, thanks.

  • Added doc comments for _selectionWidthStyleForMaxLines and introduced a documented _selectionHeightStyleForMaxLines.
  • Updated constructor initialization to use _selectionHeightStyleForMaxLines(maxLines: maxLines) for consistency with width style initialization.
  • Re-ran targeted checks:
    • flutter analyze packages/flutter/lib/src/widgets/editable_text.dart
    • flutter test packages/flutter/test/widgets/editable_text_test.dart --plain-name "selection width style"

}
// Multi-line selections should not be extended to match other lines'
// widths by default.
return ui.BoxWidthStyle.tight;

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.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi Renzo, made the suggested changes. now defaultSelectionWidthStyle always returns BoxWidthStyle.tight

@Renzo-Olivares Renzo-Olivares May 1, 2026 •

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.

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:

  1. Switch to tight like we are now. File an issue for the native selection behavior that extends the highlight to the width of the input field.
  2. Keep the existing default, and fix the issue in _TextHighlightPainter located in editable.dart. Essentially split the selection highlight into two calls to getBoxesForSelection, where the last line in the selection has a width style of tight. 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.

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.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

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.

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.

@Renzo-Olivares

Copy link
Copy Markdown
Contributor

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 tight for the default selection width style.

@Renzo-Olivares Renzo-Olivares 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.

Left a review.

@Renzo-Olivares Renzo-Olivares added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label Apr 28, 2026
@anazr9

anazr9 commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

hi @Renzo-Olivares thanks for the review, I have made the changes based on your feedback and pushed the updated code.

@github-actions github-actions Bot removed the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label Apr 29, 2026
@Renzo-Olivares Renzo-Olivares added the CICD Run CI/CD label May 1, 2026

@Renzo-Olivares Renzo-Olivares 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.

Thank you for the changes @anazr9, followed up in #185239 (comment)

@flutter-dashboard

Copy link
Copy Markdown

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 package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #185239 at sha d9b64e9

@flutter-dashboard flutter-dashboard Bot added the will affect goldens Changes to golden files label May 1, 2026
return ui.BoxWidthStyle.tight;
}
return ui.BoxWidthStyle.max;
return ui.BoxWidthStyle.tight;

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.

Let's also change the default selectionWidthStyle in RenderEditable back to tight. That would resolve #180311 as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have changed the selectionWidthStyle in RenderEditable to tight

skip: kIsWeb, // [intended]
);

testWidgets('EditableText uses tight selection width style by default', (

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.

I suggest we use a scuba for this test similar to 'default text selection height style' test in this file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have updated the test case to match similar to default text selection height style test

@Renzo-Olivares Renzo-Olivares added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 9, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label May 9, 2026
@anazr9

anazr9 commented May 9, 2026

Copy link
Copy Markdown
Contributor Author

hi Renzo-Olivares , I have made the suggested changes, please review. Thanks !

@github-actions github-actions Bot removed the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 9, 2026
);

await tester.pumpWidget(
MaterialApp(

@Renzo-Olivares Renzo-Olivares May 13, 2026 •

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.

nit: MaterialApp -> TestWidgetsApp. In general we should not import or continue to use Material components in widgets library tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh okay, I have changed it from MaterialApp to TestWidgetsApp.

);
}, variant: TargetPlatformVariant.all());

testWidgets('Explicit selectionWidthStyle is honored for multiline EditableText', (

@Renzo-Olivares Renzo-Olivares May 13, 2026 •

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.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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 Renzo-Olivares 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.

@anazr9 thank you for your patience. Left a few comments about the tests otherwise changes are looking good.

@Renzo-Olivares Renzo-Olivares added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 13, 2026
@github-actions github-actions Bot removed the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label May 13, 2026
@anazr9

anazr9 commented May 13, 2026

Copy link
Copy Markdown
Contributor Author

Hi @Renzo-Olivares thanks for the review, I have gone through your comments and made the suggested changes for the test file.

@LongCatIsLooong
LongCatIsLooong self-requested a review May 14, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems CICD Run CI/CD framework flutter/packages/flutter repository. See also f: labels. will affect goldens Changes to golden files

Projects

None yet

5 participants