-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Objective
One of our core goals is to make Flutter Web feel more idiomatic and natural on the web. A key part of this is to align the behavior of our text inputs to be more consistent with how text inputs behave on the web. This has major implications given how many impactful features branch out of a simple text box (spellcheck, autofill, etc) that web users are conditioned to expect to work. So when text inputs don’t work on Flutter Web apps exactly the way they do elsewhere on the web, it has a glaring impact on UX.
Problems
Clashing styles
We currently delegate all of the rendering of text inputs to the framework rather than the browser.
- When an
<input>element is created, we apply CSS to make these elements and aspects of these elements (content, selection caret, selection highlight, etc) invisible. By resetting the browser’s default styling, we enable Flutter to have full control over the look and feel of our text inputs. - This has the potential to cause some issues via a “clashing” of styles. The styles used to hide our text inputs don’t always work consistently across every combination of browsers and platforms, which can lead to strange rendering behavior. For example, in [Web][iOS]: Text field selection with
obscuredText: truehas grey selection #99918, iOS Safari does not support::selectionpseudoelement styles, which is the method we use to make browser selection transparent. This leads to a clash of styles that creates two overlapping selections, which makes inputs not feel quite right in Flutter Web apps on iOS Safari.
Lazily rendered inputs
We don’t render <input> elements immediately. They are created “as needed” when the user initially focuses on any given text input. They also cease to exist when you blur.
- This causes some complexity with autofill functionality. Without all of the inputs rendered immediately, we can’t leverage the browser’s native behavior to autofill multiple inputs on a page. Custom logic has been added to enable autofill to work in Flutter apps today.
- Recreating the browser-native autofill behavior is no simple task. This added complexity can create difficulties in the maintenance and debugging of autofill issues.
Related issues
- Selection:
- Up and down arrow keys miscalculate the cursor position in a TextField #79305
- [web] Text selection toolbar doesn't show up on first interaction with SelectableText #77076
- [Web] Android textfield selection shows two handles and sometimes subsequently changes selection by one character #94130
- [Web][iOS]: Text field selection with
obscuredText: truehas grey selection #99918 - [web] TextField double caret on iOS #70841
- Flutter web textfield on iOS: cursor goes to completely wrong place after tap on text #124483
- Multiline TextField text selection randomly changes on right click Web #134024
- [web][Safari-iOS][Chrome-Android] TextField cursor doesn't move to the clicked position #95958
- [EditableText] value should be selectable via double click on web in edit mode #138978
- Autofill:
- Autofill on web, while scrolling gets fixed over the screen. #118337
- Autofill on web is only activated after clicking twice on the TextField #66356
- [web] - Password managers can't autofill until after focusing on inputs due to lazy-loaded inputs #127694
- [web] 1Password autofill adds colored box over text field #125125
- IME:
- Flutter web's TextField displays gibberish for Unicode inputs, such as Korean characters (CJK) #138288
- Multiline TextField misbehaves on korean inputs only on web #134797
- [Web] When entering Korean in the TextField, there's a space at the bottom, and the first character composing weird. #134269
- [Web] TextField displays wrong text when entering Chinese #126066
- [Web] Multibyte characters are displayed incorrectly when TextField goes multiline #98817
- Other native behavior:
- Spellcheck on Flutter Web #40682
- [Web]: TextField
undooption from selection bar is not available after the TextField loses focus #104082 - [iOS Web] TextField does not advance to next input field via up/down arrow #96199
- The auto correction incorrectly highlights the text entered in TextField on iOS devices running on mobile browser. #168322
- [Firefox] macOS emoji picker doesn't input an emoji under Firefox to
TextFielddue to focus being lost for too long #168588
Solution
The above problems highlight an interesting relationship between Flutter and the browser. In some instances, we are fighting against the browser (e.g. hiding <input> els) and in other instances we’re adding a lot of complexity to our text editing system in order to enable browser-native behavior to work (autofill).
An alternative approach might be to work with the browser to leverage its native behavior as much as we can within the context of Flutter apps.
Platform Views
One way this could be accomplished is by using platform views. Platform views allow you to embed native views in a Flutter app. In the context of Flutter Web, we could use platform views to eagerly render <input> elements.
Additionally, we would need the browser to take responsibility from the framework for the styling of certain aspects of the input:
- Content
- Selection highlight
- Selection caret
- Context menus / mobile toolbars
Benefits
- By aligning the functionality of our text inputs more closely with the browser, we can better achieve idiomatic behavior of Flutter Web text inputs and all of the baked-in features that browsers provide for these inputs.
- We can greatly simplify our codebase (especially in
engine) by leveraging pre-existing browser features (e.g. autofill) rather than trying to recreate them. A simplified codebase can help us improve our velocity, maintain our code more effectively, and debug issues more efficiently. - We can fix browser-specific rendering issues for text inputs, some of which have no known workarounds in our current system. By delegating the styling of content, carets, selections, and context menus to the browser, we can achieve a more native experience on a multitude of platforms.
Tradeoffs
- The framework does a great job of giving devs the ability to customize text inputs, potentially to a greater degree than the browser allows. Delegating styling responsibilities to the browser comes at the expense of losing this greater degree of customizability.
Potential issues / Unknowns
- Platform views are performance-optimized and will disappear outside of the viewport. If
<input>elements disappear outside of the viewport, this will break autofill functionality. - Could platform views cause performance issues in CanvasKit due to interleaving of
<input>elements between<canvas>sheets? Is a page with many inputs feasible when taking into account this performance cost? - Can we rewrite the text editing system in a way that continues to integrate well with the Framework’s code philosophy of being platform-agnostic?
- How will this work when semantics are enabled? Will this solution play well with semantics mode?
- Password autofill is currently broken for inputs within the shadowDOM in Chrome - but platform views need to be rendered within
<slot>s and have to exist in the shadowDOM