Flutter

How to make a beautiful modal in Flutter

Opening a modal on an app is really simple. In fact, why shouldn’t it be? You just have to click on a button and “Et voila”, you have a beautiful modal opened on your app. At least that’s what I thought before trying for one week to find the best way to implement a modal on the app I was working on.

Our goal was to upgrade the actual implementation of a modal by adding interaction with the background :

To achieve the perfect modal, we first have to ask ourselves what we really know about a modal and its use, and then, we can compare the existing solution that matches our requirements to use the best one (or as I call it, “Compare to conquer”).

What is a modal ?

To my surprise, the first difficulty I encountered wasn’t a technical one. It was the actual definition of the object. We stated that we wanted a modal here, but we later realized that what we actually needed was the behavior of a bottom sheet.

Each “modal” package we tested has the same behavior :

  • You have a method you can call that pushes a route to the navigator. This has some advantages of course; one of them is being able to call this method everywhere on your app really easily. But pushing a route to the navigator negates all the gesture interactions we could have with the page in the background.

This was the previous implementation we had in place in our app, so it wouldn’t work out with our new requirement, however, it was a pretty practical one considering you can easily control your modal or when it should be dismissed.

Here is the implementation of the function:

So after finding this difference out, we weren’t seeking for modal package anymore but rather “sheet” or “bottom-sheet” like ones.

Which package to use

After a short research, I found two packages that meet the minimum requirement I was looking for: Flutter DraggableScrollableSheet and SlidingSheet.

It was tough to decide which one to use with how similar both were but here is a little comparison of them.

Common ground

Let’s see what both packages have in common first before making any decision.

A negative point I get from both packages compared to a classic “modal” is that the modal is now a widget. So compared to a modal, you can’t easily access it from anywhere and it actually belongs to one page. This could be seen for some as a good point, it is easier to restrain its usage.

Being a widget has another impact, if you don't handle it, modal will be built in every build of your page.

Another common point is that both handle the snaps the same way by having a list of the different heights where the modal should snap. These heights go from 0 to 1 with 1 being the size of the screen.

Which one is the best

Let’s now face which one I recommend for you to use.

On my right the official flutter component: DraggableScrollableSheet!

And on my left, a package with 633 likes and 96% of popularity : Sliding sheet!

Let the real deal begin.

To start off this battle we see that each contestant has their own style :

The flutter component should be added inside a Stack in order to be used where the package should be wrapping our page.

In the example, the CustomSlidingSheet is an implementation of the package Sliding sheet and CustomBottomSheetModal is an implementation of the DraggableScrollableSheet component.

I have no preferences whatsoever but I find it relevant to highlight this.

Another difference is how to hide the modal from the build. For the SlidingSheet, you have a function on the controller to hide it :

If this is great with an onTap or any function call, we had some problems setting it up by dismissing the modal by dragging it down.

In fact, we tried a simple implementation that uses the controller providing the size to determine if yes or no the modal was on the screen.

On paper, the size of the controller should be 0 when we drag it down (corresponding to the value of snap being 0). But code is not always perfect and apparently, we had a 3.22571e-17 difference in value which is not a lot but sufficient enough not to be 0.

For DraggableScrollableSheet, we implemented a small hack which is the following:

We created a boolean ++code>shouldShowModal++/code> and conditioned the widget appearance like this:

This boolean is set to true when we want to display the modal.

To handle dismissing the modal by dragging, we used the size given by the controller of the modal. We created a small threshold under which we set the boolean to false to hide the component.

Don’t forget to set the initialChildSize of your modal above the value of your threshold otherwise, you won't be able to open the modal.

At this point in the article, you might think that the title is total clickbait (which is true). However, If I know one thing, it is that a smooth animation can upgrade something pretty to something beautiful. So here is the next comparison, which modal is easier to animate?

Well here is the deal:

With DraggableScrollableSheet, you have to choose the way your modal opening/closing is animated:

So you have control on the animation itself and the duration.

For SlidingSheet,

You have a function: ++code>snapToExtent++/code> that animate the modal for you and only leave the choice of the duration.

So you can’t directly control the type of animation. But if you want to modify the code of the package you can easily change that by adding a prop to this method. Here is the code of the modified ++code>snapToExtent++/code> method:

So you can control the animation of your modal with both solutions, however, it is more painful to change the package itself and if it is updated you may have conflicts.

But speaking about updates, there will most likely be none. At least for SlidingSheet. Why?? because the github repository of the package is closed, and it has been a while since the package has been updated.

About the DraggableScrollableSheet package, it is maintained by flutter so I am not worrying too much about it.

My last point in this comparison would be to compare how easy to implement both solutions are.

And on this point, I found that both were pretty easy and you just have to follow the documentation of each package which is really clear.

Final thoughts

If you don’t know which package to use at this point of the article, well then you can reread from the beginning. But if you are too lazy to do that, here is the recap of what I observed :

DraggableScrollableSheet SlidingSheet
Dismiss on background tap ⚠️ Can be added manually with the controller
Handle scrolling ✅ still experimental but it works
Implementation A component you can put in a stack A component that wraps your page
Handle different animations ⚠️  Need to modify the package code, you can only access the animation duration
Is maintained ❌ No more maintained
Easy to use/implement

I don’t want to influence you on your choice (actually I do) but there seems to be a column with more green lights than the other one. On a more serious note, we decided to use DraggableScrollableSheet on our project and have been really happy with it. However, I think that SlidingSheet is a good option too but with some warning on the maintainability of this package.

So to sum up this article:

If you want to learn more about Flutter modals, you can download the example app from the video at this GitHub repository.

Développeur mobile ?

Rejoins nos équipes