Skip to content

[Web]: Click outside of text field should unfocus  #32433

Closed

Description

@kunit1

When trying the gallery example app in flutter_web I noticed that clicking away from a focused text field does not cause it to lose focus.

It is standard behaviour on the web that when a text field is focused and the mouse is clicked on a blank space on the page the field is unfocused.

Steps to reproduce on Chrome browser with a mouse and keyboard (e.g. on a desktop):

  1. Click on text field - Field is now in focus with cursor visible
  2. Click outside of text field on a blank space (not another text field) - Text field is still in focus

Activity

  1. yjbanov commented on May 9, 2019

    @yjbanov
    Contributor
  2. added this to the milestone on May 9, 2019
  3. PonyCui commented on Jun 16, 2019

    @PonyCui

    I think you should setup a TextEditingController and GestureDetector, call TextEditingController.unfocus() method after onTap.
    This is not a BUG, it's a common activity.

  4. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Jul 26, 2019
  5. caseyryan commented on Sep 8, 2019

    @caseyryan

    I think you should setup a TextEditingController and GestureDetector, call TextEditingController.unfocus() method after onTap.
    This is not a BUG, it's a common activity.

    There is no"unfocus" method on TextEditingController, it's on a FocusNode.
    But there's still another problem. I've seen a lot of topics where people recommend to wrap the whole app in a GestureDetector to detect a tap outside a TextField and request a new focus node. It works only on blank spaces. If I tap on some FlatButton or anything that also has its gesture detector, this approach doesn't work

  6. added
    P2Important issues not at the top of the work list
    on May 29, 2020
  7. kunit1 commented on Jun 8, 2020

    @kunit1
    Author

    This was working at some point and is now broken again.
    cc/ @nturgut Is this related to this change? PR18743

  8. caseyryan commented on Jun 14, 2020

    @caseyryan

    For those who needs this functionality I've created a hack. You can use my package https://pub.dev/packages/flutter_multi_formatter which includes a widget called Unfocuser
    there's also and example with a usecase

  9. added
    P3Issues that are less important to the Flutter project
    and removed
    P2Important issues not at the top of the work list
    on Jun 16, 2020
  10. removed this from the milestone on Aug 17, 2020
  11. steffenhaak commented on Nov 3, 2020

    @steffenhaak

    On Firefox, this actually breaks text fields completely. If you do an outside click, it is no longer possible to enter any text in the text field, despite the cursor still being shown. Maybe there is another bug ticket for that? The only chance to get the textfield working again is by temporarily focusing on another text field, if one is available on the screen.

    This is reproducible in the flutter gallery app: https://gallery.flutter.dev/#/demo/text-field

    In my opinion, this issue should get ranked higher, as this bug currently breaks every flutter web app using a text field for Firefox users.

  12. 1 remaining item

  13. steffenhaak commented on Nov 3, 2020

    @steffenhaak

    @nturgut thanks for your reply. After writing my comment, I actually thought the same and already opened a separate issue: #69680

  14. venkatd commented on Dec 11, 2020

    @venkatd

    @caseyryan I adopted your version in our application but I wanted to make sure the simplifications I made don't have any impact on edge cases. Thanks for that workaround I was fighting with our code for a while!

    Are there any edge cases this version could cause for us? It has seemed to work OK for us so far.

    import 'package:flutter/rendering.dart';
    import 'package:flutter/widgets.dart';
    
    class Unfocuser extends StatelessWidget {
      const Unfocuser({Key key, this.child}) : super(key: key);
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return Listener(
          onPointerUp: (e) {
            final rb = context.findRenderObject() as RenderBox;
            final result = BoxHitTestResult();
            rb.hitTest(result, position: e.position);
    
            final hitTargetIsEditable =
                result.path.any((entry) => entry.target is RenderEditable);
    
            if (!hitTargetIsEditable) {
              final currentFocus = FocusScope.of(context);
              currentFocus.unfocus();
            }
          },
          child: child,
        );
      }
    }

    I wrap our entire app in this widget.

  15. caseyryan commented on Dec 12, 2020

    @caseyryan

    @caseyryan I adopted your version in our application but I wanted to make sure the simplifications I made don't have any impact on edge cases. Thanks for that workaround I was fighting with our code for a while!

    Are there any edge cases this version could cause for us? It has seemed to work OK for us so far.

    import 'package:flutter/rendering.dart';
    import 'package:flutter/widgets.dart';
    
    class Unfocuser extends StatelessWidget {
      const Unfocuser({Key key, this.child}) : super(key: key);
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return Listener(
          onPointerUp: (e) {
            final rb = context.findRenderObject() as RenderBox;
            final result = BoxHitTestResult();
            rb.hitTest(result, position: e.position);
    
            final hitTargetIsEditable =
                result.path.any((entry) => entry.target is RenderEditable);
    
            if (!hitTargetIsEditable) {
              final currentFocus = FocusScope.of(context);
              currentFocus.unfocus();
            }
          },
          child: child,
        );
      }
    }

    I wrap our entire app in this widget.

    I see you have removed IgnoreUnfocuser. This will not let you force any inputs to ignore this feature if you need it somewhere. I don't think there will be any other side effects. So if not being able to avoid unfocuser is ok with you then your version will work

  16. venkatd commented on Dec 12, 2020

    @venkatd

    @caseyryan thanks! Looks like I needed the Unfocuser after all so I added it back:

    import 'package:flutter/rendering.dart';
    import 'package:flutter/widgets.dart';
    
    class Unfocuser extends StatelessWidget {
      const Unfocuser({Key key, this.child}) : super(key: key);
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return Listener(
          onPointerUp: (e) {
            final rb = context.findRenderObject() as RenderBox;
            final result = BoxHitTestResult();
            rb.hitTest(result, position: e.position);
    
            for (final e in result.path) {
              if (e.target is RenderEditable ||
                  e.target is IgnoreUnfocuserRenderBox) {
                return;
              }
            }
    
            final primaryFocus = FocusManager.instance.primaryFocus;
    
            if (primaryFocus.context.widget is EditableText) {
              primaryFocus.unfocus();
            }
          },
          child: child,
        );
      }
    }
    
    class IgnoreUnfocuser extends SingleChildRenderObjectWidget {
      IgnoreUnfocuser({@required this.child}) : super(child: child);
    
      final Widget child;
    
      @override
      IgnoreUnfocuserRenderBox createRenderObject(BuildContext context) =>
          IgnoreUnfocuserRenderBox();
    }
    
    class IgnoreUnfocuserRenderBox extends RenderPointerListener {}
  17. Apollo108 commented on Jan 29, 2021

    @Apollo108

    @venkatd hi, thank you for your solution, but seems it hides keyboard when one starts scrolling, even if the dragging point is the focused textfield. Is there any way to solve this?

  18. caseyryan commented on Jan 29, 2021

    @caseyryan

    @venkatd hi, thank you for your solution, but seems it doesn't allow scrolling, even if I start dragging from the focused textfield. Is there any way to solve this?

    What do you mean? This solution has nothing to do with scrolling. You can use any scrollable widgets from CustomScrollView to SingleChildScrollView or any other wrapped in my Unfocuser widget. What Unfocuser does is simply checking what kind of render box is under a tap point and if it's not a text input it requests an empty focus

    Unfocuser(
       child: CustomScrollView(...),
    )

    This will allow scrolling. I use it in lots of apps.
    If scrolling doesn't work in your code, the reason is somewhere else

  19. Apollo108 commented on Jan 29, 2021

    @Apollo108

    I'm sorry, I meant it hides keyboard on scroll start, even if I drag with focused field.

  20. caseyryan commented on Jan 29, 2021

    @caseyryan

    I'm sorry, I meant it hides keyboard on scroll start, even if I drag with focused field.

    Yep, it does not check if you're scrolling or not. It's not a bug it's just lack of such functionality. I will probably add it in the next release of flutter_multi_formatter if I have time for this this weekend.
    Please, add a ticket with the functionality you need here https://github.com/caseyryan/flutter_multi_formatter
    I can't do it myself at the moment

  21. added
    customer: crowdAffects or could affect many people, though not necessarily a specific customer.
    on Mar 3, 2021
  22. MatthewLM commented on Apr 21, 2021

    @MatthewLM

    Thanks above for the workarounds. I do hope this will be resolved within flutter as the Unfocuser class provided by flutter_multi_formatter is a hack and doesn't work perfectly. To ensure that the toolbar buttons work correctly, it doesn't defocus when a RenderParagraph is hit. This prevents defocusing working when clicking on particular widgets. Maybe there is a way to hack it further to determine when the toolbar buttons are specifically tapped but I'd like to see built-in support.

  23. Wissperwind commented on Jun 2, 2021

    @Wissperwind

    In December 2020 you posted some unfocuser workarounds. I tried the one from the first post.
    I can indeed click into white space and the text field looses focus. But I can't mark things in a text field anymore. For example to delete the whole content. Is there a workaround version that does not include this bug?

  24. caseyryan commented on Jun 2, 2021

    @caseyryan

    In December 2020 you posted some unfocuser workarounds. I tried the one from the first post.
    I can indeed click into white space and the text field looses focus. But I can't mark things in a text field anymore. For example to delete the whole content. Is there a workaround version that does not include this bug?

    There is no such bug. All this functionality works fine. Maybe exactly this solutions has some bug (idk) but I'm totally sure the one from my plugin https://pub.dev/packages/flutter_multi_formatter works perfectly. I use it in all my projects and never came across anything like this.
    If Unfocuser from flutter_multi_formatter package still won't work for you, could you provide some minimal example that reproduces the bug?

  25. 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.

  26. 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: desktopRunning on desktopc: new featureNothing broken; request for a new capabilitycustomer: crowdAffects or could affect many people, though not necessarily a specific customer.frameworkflutter/packages/flutter repository. See also f: labels.platform-webWeb applications specifically

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions