Skip to content

Can't swipe to dismiss scrollable Bottom Sheet #36283

Open

Description

@cpboyd

Per @dnfield #31739 (comment)

Use case

See the Crane Material sample and Google I/O 2019

These both feature a bottom sheet that slides up (in the case of I/O, you select "Events" and the hit the "Filter" FAB) and scrolls.

With the I/O app, if you continue to swipe down when scrolled to the top, it will start to drag and then dismiss when a threshold is reached.

If the threshold is not reached (or you swipe upwards) then the bottom sheet will not be dismissed and it'll rebound to the top of the screen.

Proposal

I'd think this should be a part of DraggableScrollableSheet as mentioned in #31739, but maybe it makes sense to bake the logic into the Bottom Sheet itself?

I've tried both modal and non-modal bottom sheets with and without the DraggableScrollableSheet, and can't seem to make this work as is.

The current issue with the DraggableScrollableSheet is that you can't have the sheet be maximized all the time. (Since, as I mentioned in #31739 (comment), any swipe will immediately dismiss the BottomSheet rather than scroll the CustomScrollView)

Activity

  1. added
    f: gesturesflutter/packages/flutter/gestures repository.
    p: material_uimaterial_ui package in flutter/packages
    f: scrollingViewports, list views, slivers, etc.
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Jul 16, 2019
  2. added this to the milestone on Jul 16, 2019
  3. dnfield commented on Jul 16, 2019

    @dnfield
    Contributor

    It would be super helpful if you had a gif/youtube/video of this behavior. I think I know what you're talking about, but I haven't used the apps you're referring to and I'm not sure which part to look for.

  4. cpboyd commented on Jul 16, 2019

    @cpboyd
    Author

    @dnfield See https://www.youtube.com/watch?v=95MUkecOta4

    I wasn't able to get it to "rebound" while recording, but I'm pretty sure I've seen it bounce back to the top if a certain threshold isn't met.

    Edit: First dismiss is dragging from the app bar. Second dismiss is from dragging the list after reaching the top (similar behavior to DraggableScrollableSheet). I had to release (after reaching the top of the list) and then drag down again.

  5. dnfield commented on Jul 16, 2019

    @dnfield
    Contributor

    I thought the bottom sheet was working this way - the first time you hit the top of the list it will bounce, the second time it will actually drag down. I feel like I'm missing something in the desired behavior though.

  6. cpboyd commented on Jul 17, 2019

    @cpboyd
    Author

    @dnfield I've tried both

            _scaffoldKey.currentState.showBottomSheet(
              _buildBottomSheet,
            );

    and

            showModalBottomSheet(
              context: context,
              builder: _buildBottomSheet,
              isScrollControlled: true,
            );

    where _buildBottomSheet is a Widget Function(BuildContext) that contains a CustomScrollView.

    Nothing seems to do the drag-to-dismiss except when wrapped in a DraggableScrollableSheet.

    Do I need to pass in a special ScrollController?

  7. dnfield commented on Jul 17, 2019

    @dnfield
    Contributor

    You have to use a DraggableScrollableSheet for that behavior to work.

  8. cpboyd commented on Jul 17, 2019

    @cpboyd
    Author

    @dnfield Ok. So how do I get the DraggableScrollableSheet to rebound back to maxChildSize unless the minChildSize threshold is passed?

    I'm currently using this:

    DraggableScrollableSheet(
          builder: scroll,
          initialChildSize: 1.0,
          minChildSize: 0.9,
        );

    Unfortunately, the user can wind up with it sticking between 1.0 and 0.9, which looks a little awkward.

  9. dnfield commented on Jul 17, 2019

    @dnfield
    Contributor

    Unfortunately this isn't really documented well at all, and in trying to do it I'm finding some other bugs.

    I think this should be possible, but it may take me a little while to get back to it. If you have a proposal for fixing it we could review a PR for it as well.

  10. rbluethl commented on Feb 7, 2020

    @rbluethl

    Are there any updates on this?

  11. jamesblasco commented on Apr 15, 2020

    @jamesblasco
    Contributor

    Hello @rbluethl, I built a package that supports scrollable ModalBottomSheets.
    https://github.com/jamesblasco/modal_bottom_sheet

    Instead of showModalBottomSheet, it would be:

    showMaterialModalBottomSheet(
      context: context,
      builder: (context, scrollController) => Container(),
    })

    Hope it can help you until this is officially implemented.

  12. 34 remaining items

  13. kanhaiyabigbasket commented on Jun 27, 2024

    @kanhaiyabigbasket

    any update?

  14. notsag-dev commented on Jul 28, 2024

    @notsag-dev

    For those looking for at least a workaround for not being able to hide the bottom sheet by dragging it down when the inner list size exceeds the size of the bottom sheet: Pop the context from the inner list (this makes the bottom sheet hide), when there's a top overscroll on that list and the user is currently dragging.

    This doesn't progressively hides the bottom sheet when you drag it down, but it detects the gesture and hides it all at once. This is the closest I was able to get to an acceptable behavior, while still being a patch. For the case in which the inner list is smaller than the outer sheet it does work as expected.

    My bottom sheet:

      showModalBottomSheet(
        context: context,
        enableDrag: true,
        isScrollControlled: true,
        builder: (BuildContext context) {
          return FractionallySizedBox(
              heightFactor: 0.9,
              child: DraggableScrollableSheet(
                maxChildSize: 1,
                minChildSize: 1,
                initialChildSize: 1,
    

    The inner scrollable widget needs these state fields:

      final ScrollController scrollController = ScrollController();
      bool isAtTop = true;
      bool userIsDragging = true;
    

    Add listener in the initState for the scroll:

        scrollController.addListener(scrollListener);
    

    The listener detects when you are at the top of the list:

      void scrollListener() {
        setState(() {
          isAtTop = scrollController.offset <= 0;
        });
    

    And in the build method use a NotificationListener to detect also when the user is currently dragging and the top overscroll is less than a certain value (-3 in this case), the context is popped and the bottom sheet hides:

    NotificationListener<ScrollNotification>(
        onNotification: (ScrollNotification scrollNotification) {
          if (scrollNotification is ScrollStartNotification) {
            if (isAtTop &&
                scrollNotification.dragDetails != null) {
              userIsDragging = true;
            }
          } else if (scrollNotification
              is ScrollEndNotification) {
            userIsDragging = false;
          } else if (scrollNotification
              is OverscrollNotification) {
            if (isAtTop &&
                userIsDragging &&
                scrollNotification.overscroll < -3) {
              Navigator.pop(context);
              return true;
            }
          }
          return false;
        },
        child: PagedListView<int, Comment>(
            pagingController: pagingController,
            scrollController: scrollController,
            physics: const ClampingScrollPhysics(),
            primary: false,
            shrinkWrap: true,
            ...
    

    I hope this helps until we have a proper solution.

    Note: If you wonder why the drag event is needed: You don't want the momentum of the scroll up to hide your bottom sheet. This also causes a top overscroll < 0 when it reaches the beginning of the list.

    Edit: It's necessary to set ClampingScrollPhysics for the list physics as for iOS the default is BouncingScrollPhysics and the overscroll notification doesn't work in that case.

  15. ziqq commented on Jul 31, 2024

    @ziqq
    Contributor

    The solution is not quite correct and requires improvements from the flutter team. The point is that when the scroll ends and the top of the screen is reached, the bottom sheet closes immediately, which does not meet expectations.

    Use mobile breackpoint: https://dartpad.dev/?id=ee0a9552f654de9fe24adbbdba95fc2a

    Expected: https://github.com/user-attachments/assets/964d906c-2b0e-45be-be4d-bfeb3ba0d5fc

    In fakt: https://github.com/user-attachments/assets/eb886651-5f5e-419f-ad21-98dfc0cdfa21

  16. notsag-dev commented on Jul 31, 2024

    @notsag-dev

    This isn't an actual solution but a patch as I said. For my use case this is better than having a bottom sheet that can only be dismissed from the handle when the inner list exceeds the bottom sheet size. I'm also looking forward to an actual solution.

  17. shahmirzali49 commented on Oct 8, 2024

    @shahmirzali49

    any update?

  18. JunseungBaek commented on Nov 19, 2024

    @JunseungBaek

    This is the exact same behavior as YouTube comments. Hope this gets resolved soon.

  19. rydmike commented on Mar 15, 2025

    @rydmike
    Contributor

    Drag to dismiss scrollable bottom sheet?

    The bottom sheet is not necessarily limited to Material design, however even the Material specification refers to being able to swipe down to dismiss a sheet, here:

    https://m3.material.io/components/bottom-sheets/guidelines#22deb8a2-3513-4a2e-aa47-c64875e15e12

    Image

    Currently this is not possible in Flutter when we have a sheet with scrolling content, as all in this thread have experienced. At least it is not possible not without some quite hacky and/or poorly working solutions. If anybody has a well working simple solution please do share it.

    Predictive back (Android & Material-3)

    A new thing in Material-3 is the predictive back swipe that also allows you to close a bottom sheet. This is something that is also not yet supported, especially with the sheet shrink animation.

    It is shown and demonstrated here:

    https://m3.material.io/components/bottom-sheets/guidelines#3d7735e2-73ea-4f3e-bd42-e70161fc1085

    lvpbtr1r-GM3-Components-BottomSheets-Guidelines-2-v01.mp4

    Flutter does not support this pattern either.

    Both these cases should of course have easy built-in support in Flutter. For the first case it has been open since 2019, without any good or well known solution, which is quite sad, the second case is still quite a new pattern so that is more understandable, most native Android apps do not support it yet either.

  20. blehn commented on May 14, 2025

    @blehn

    Been working on a Flutter project for about a month. Going to have rebuild the whole thing in Swift specifically because of this issue. 6 years and no attention from the official team.

    Warning: do not use Flutter for serious applications. You will get burned eventually.

  21. tmaihoff commented on May 14, 2025

    @tmaihoff

    For the ios version of my app I use this package https://pub.dev/packages/modal_bottom_sheet where the function works just as intended. There, I can scroll down to dismiss the sheet.

    I haven't had the time to investigate and compare the code, but maybe we could find a potential solution there as well.

    @blehn and maybe this package could be an option for you as well before you rewrite everything.

  22. tmaihoff commented on Jun 5, 2025

    @tmaihoff

    So I had a deep conversation with AI this evening and we were able to find a solution.
    Here is the gist containing the updated bottom_sheet_fix.dart file.

    For now, just paste it into your project and import it like this:

    // hide the original function if you need the material package
    import 'package:flutter/material.dart' hide showModalBottomSheet; 
    import './bottom_sheet_fix.dart' as fixed;
    ... 
        // Then use it like this.
        fixed.showModalBottomSheet(...)
       // Or just rename the function from the gist and call the renamed function.
    ...

    Please report if it works for you as well!

  23. Pluxury commented on Apr 7, 2026

    @Pluxury

    So I had a deep conversation with AI this evening and we were able to find a solution. Here is the gist containing the updated bottom_sheet_fix.dart file.

    For now, just paste it into your project and import it like this:

    // hide the original function if you need the material package
    import 'package:flutter/material.dart' hide showModalBottomSheet;
    import './bottom_sheet_fix.dart' as fixed;
    ...
    // Then use it like this.
    fixed.showModalBottomSheet(...)
    // Or just rename the function from the gist and call the renamed function.
    ...

    Please report if it works for you as well!

    Thanks! Your work with AI has helped

  24. knotbin commented on Jul 10, 2026

    @knotbin

    No updates from any Flutter team member on this since July 2019, exactly 7 years ago.

    The issue persists and goes against the Material spec and Apple's native behavior.

  25. added
    packageflutter/packages repository. See also p: labels.
    and removed
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Aug 17, 2026
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

    P2Important issues not at the top of the work listc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Fluttercustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: gesturesflutter/packages/flutter/gestures repository.f: scrollingViewports, list views, slivers, etc.p: material_uimaterial_ui package in flutter/packagespackageflutter/packages repository. See also p: labels.team-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions