[Liminal UI] Replace `SwipeableDrawer` with a more flexible drawer implementation
Migrate to a new drawer implementation, which will act as a foundation for further work on the Command Center.
Ignore background glow behavior, but otherwise ensure no behavioral changes from current implementation.
MUI’s SwipeableDrawer has several limitations that make further Command Center development difficult without resorting to hacky workarounds.
Let’s migrate to a more flexible drawer implementation that will grow with our needs.
Features the new drawer should ideally support
Here's a list of features the new drawer implementation will need to support.
We shouldn't implement any new features in this PR, but the chosen component/library should be capable of them so we can proceed confidently knowing the solution can scale to the tasks ahead.
-
Gesture support
- The ability to swipe the drawer to close it, as with the current implementation.
-
Performant observability of drawer height
- We need to be able to track the drawer as it opens and closes – whether the drawer is being open/closed programatically, or gradually via the swipe gesture.
-
Snap points
- When we come around to implementing the "Expanded View", we will need the drawer to expand further once open to a second stage. (See image 3.)
- These are called "snap points" in most drawer implementations.
- The user should be able to swipe up (between image 2 to 3) to move to the next snap point, or tap the arrow.
- So we will need both gesture and programatic ability to switch between snap points.
- We will also need to be able to switch out the contents of the drawer between the snap points, so we'll need some way to detect the current snap point.
-
Behaves gracefully with the keyboard
- When the mobile keyboard opens, the drawer should respond predictably.
- This will be especially relevant when implementing the Command Center’s search view. (See image 4.)
-
Drawer can fully unmount when closed
- The current MUI drawer stays mounted in the DOM even when it's closed. For more memory and performance optimisation, it would be great to identify a library where we can choose to unmount the drawer when it's closed.
Also, some nice-to-haves:
-
Supports horizontal (sidebar/hamburger menu) orientation
- At some point we'll need to implement the new design for the Sidebar – could be cool to find a solution that would work for this, too
Potential candidates
I only did a cursory review of these, but they seem like good starting points for exploration:
@fbmcipher I think we should use react-modal-sheet for the new drawer component.
After researching the options, this one meets nearly all our needs and is actively maintained.
react-modal-sheet
This library is reliable and handles the critical features we need:
- Snap Points: It fully supports snap points, whether the user swipes between them or we trigger them programmatically.
-
Gestures & Observability: It uses
framer-motion, so swiping to close is smooth. We get callbacks to track the drawer's height and know the current snap point. -
Keyboard & Unmounting: It includes support for managing the mobile keyboard without layout issues, and we can set it to fully unmount from the DOM when closed (
unmountOnClose), which helps with performance. - The Trade-off: The only feature it lacks is horizontal orientation; it is only a vertical bottom-sheet.
Why the Other Options Didn't Work Out
The main challenge is that libraries supporting horizontal movement are either unstable or lack snap points:
- Vaul: This is the only library that supports both horizontal movement and snap points. However, it is unmaintained right now, making it too risky for a core component.
- React Spring Bottom Sheet: The library's last update was three years ago and it doesn't support React 19. We would have to rely on community forks for current React versions, which adds dependency uncertainty.
- MUI SwipeableDrawer: It's stable, but it does not support snap points. This fails a core requirement for our expanded view.
-
Building it ourselves (via
react-use-gesture): While this guarantees horizontal support, it requires building all the physics, accessibility, and state management from scratch. The effort outweighs the benefit sincereact-modal-sheethandles almost everything else.
Conclusion
I suggest we move forward with react-modal-sheet. It is the most stable and feature-complete component library available to us. what do you think?
@yangchristina Thank you for this detailed overview – it was super helpful.
I agree fully with your evaluation – react-modal-sheet sounds perfect. Slight shame about the lack of horizontal orientation for the sidebar, but we can just use a different library for that.
Though there's crossover between the Command Center drawer and the sidebar, the sidebar is a little simpler (it doesn't need to support snap points, for example) – so I think it'd be okay to work with a simpler/lighter library there.
Let's move forward and refactor with react-modal-sheet!