Skip to content

Not possible to de-focus a text field without clicking another focusable widget #82515

Closed

Description

@jonahwilliams

Consider a page with a focusable text field, such as the gallery. After focusing the text field, I would expect that one the web or desktop I could click outside the text field area to remove focus. However this is not possible today, I need to click another focusable widget such as a text field or leave the page.

Aside from platform adaoption, this makes it difficult or impossible to use the Shortcuts widget to on a page with text fields. The Shortcuts may not be able to gain focus again after the text field has been focused.

Since the text fields cannot receive tap events that don't hit them (in order to dispose of focus), the solution requires a new widget be introduced that can intercept focus from the text fields.

Solution: The parent focus trap. A widget introduced at either the app level or route level. On tap events, it always requests focus. This will only be granted if the tap does not hit a more specific focus node. Draft:

class FocusTrap extends StatefulWidget {
  /// Create a new [FocusTrap] widget.
  const FocusTrap({
    required this.child,
    this.focusNode,
    Key? key
  }) : super(key: key);

  final Widget child;
  final FocusNode? focusNode;

  @override
  State<FocusTrap> createState() => _FocusTrapState();
}

class _FocusTrapState extends State<FocusTrap> {
  final Map<Type, GestureRecognizerFactory> _gestures = <Type, GestureRecognizerFactory>{};
  late FocusNode _focusNode;

  FocusNode get focusNode => widget.focusNode ?? _focusNode;

  void _stealFocus(TapDownDetails details) {
    if (details.kind != PointerDeviceKind.mouse)
      return;
    focusNode.requestFocus();
  }

  @override
  void initState() {
    super.initState();
    _focusNode = FocusNode();
    _gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
        () => TapGestureRecognizer(debugOwner: this),
        (TapGestureRecognizer instance) {
          instance
            .onTapDown = _stealFocus;
        },
      );
  }

  @override
  Widget build(BuildContext context) {
    return Focus(
      autofocus: true,
      child: RawGestureDetector(
        child: widget.child,
        gestures: _gestures,
      ),
      focusNode: focusNode,
    );
  }
}

And currently introduced in the same place I was putting SelectionArea (since this is needed to make Ctrl+C and other shortcuts work reliably)

@@ -10,6 +10,7 @@ import 'package:flutter/scheduler.dart';
 import 'package:flutter/semantics.dart';

 import 'actions.dart';
+import 'base_focus.dart';
 import 'basic.dart';
 import 'focus_manager.dart';
 import 'focus_scope.dart';
@@ -841,11 +842,11 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
                             key: widget.route._subtreeKey, // immutable
                             child: Builder(
                               builder: (BuildContext context) {
-                                return widget.route.buildPage(
+                                return FocusTrap(child: widget.route.buildPage(
                                   context,
                                   widget.route.animation!,
                                   widget.route.secondaryAnimation!,
-                                );
+                                ));
                               },
                             ),
                           ),

new behavior:

Flutter.Gallery.-.Google.Chrome.2021-05-13.20-56-00.mp4

blocks: #81839

Activity

  1. added
    c: new featureNothing broken; request for a new capability
    frameworkflutter/packages/flutter repository. See also f: labels.
    a: qualityA truly polished experience
    P3Issues that are less important to the Flutter project
    on May 14, 2021
  2. jonahwilliams commented on May 14, 2021

    @jonahwilliams
    ContributorAuthor
  3. jonahwilliams commented on May 14, 2021

    @jonahwilliams
    ContributorAuthor

    and here is the current behavior: I am clicking a ton:

    Flutter.Gallery.-.Google.Chrome.2021-05-13.21-01-47.mp4
  4. SpajicM commented on May 14, 2021

    @SpajicM
  5. added
    a: text inputEntering text in a text field or keyboard related problems
    p: material_uimaterial_ui package in flutter/packages
    on May 14, 2021
  6. HansMuller commented on May 14, 2021

    @HansMuller
    Contributor
  7. pedromassango commented on Jun 5, 2021

    @pedromassango
    Member

    Nice to see this issue getting attention from the team again :)

    I believe this case should be coved as well:
    #72029 - Selection toolbar/handler should disappear when it is opened and user clicks outside of it

    @jonahwilliams will this be the default behavior? I hope it does.

  8. jonahwilliams commented on Jun 7, 2021

    @jonahwilliams
    ContributorAuthor

    I don't know what the right behavior is for mixed pointer and mouse selection. I think that would likely be a different issue

  9. pedromassango commented on Jun 7, 2021

    @pedromassango
    Member

    I don't know what the right behavior is for mixed pointer and mouse selection.

    The expected behavior is to remove the selection toolbar. I've shared more about that in #72029 (see Side Note - issue /2 section).

  10. github-actions commented on Jul 31, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  11. locked as resolved and limited conversation to collaborators on Jul 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: qualityA truly polished experiencea: text inputEntering text in a text field or keyboard related problemsc: new featureNothing broken; request for a new capabilityframeworkflutter/packages/flutter repository. See also f: labels.p: material_uimaterial_ui package in flutter/packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions