React Draggable Bottom Panel
Tags: react, ux, webdev
Published: 2021-08-21 19:01:32


> TL;DR: Source for `BottomPanel.jsx` and `BottomPanel.module.scss` is at
https://gist.github.com/josiahbryan/c220708256f7c8d79760aff37f64948f.

> Live Demo: https://josiahbryan.com/#/bottompanel-demo

I've been working on a couple of different projects lately, one involves working on the next-generation marketplace for [fringe.us](http://fringe.us), and the other project is an app for a luxury driving service.

Both of these projects called for a bottom panel that can be partially exposed and then dragged/swiped up to reveal content. 

I searched high and low and could not find any acceptable implementations of just such a UI component in React - which was rather shocking, I thought surely someone had solved this rather common UI paradigm already for React!

I found many implementations of the paradigm in non-web-React formats, here's a couple examples that show what I wanted:

* React Native: https://github.com/enesozturk/rn-swipeable-panel
* Flutter: https://github.com/enesozturk/rn-swipeable-panel

Both of those packages look beautiful and I would love to use them! However, the projects I'm working on require React in a browser, so those packages are not options.

I almost gave up on finding a solution, but yesterday I decided to give it one last try. I thought surely I can implement it myself! I first tried extracting the `SwipeableDrawer` component from @material-ui's source, but that proved incredibly painful and never got that working.

Then I tried writing a simple implementation of a drawer myself using `react-swipeable`'s awesome hook. That worked okay, but the FPS (especially on mobile) was HORRIBLE. I'm talking ~10-~12 fps when dragging. NOT accetable.

Then, almost as if by providence, I stumbled upon this section in `react-swipeable`'s docs: https://github.com/FormidableLabs/react-swipeable#how-to-use-touch-action-to-prevent-scrolling - that mentioned a package I hadn't looked at yet, [`use-gesture`](https://use-gesture.netlify.app/). By this point, I was exhausted from reading docs and thought that I would just glance at that package, but didn't think anything would be useful. Boy, was I wrong.

I read the docs in `use-gesture` and was subtly impressed. Then I found [their examples page](https://use-gesture.netlify.app/docs/examples/), which led me to their example for an "Action Sheet": https://codesandbox.io/embed/zuwji?file=/src/index.js&codemirror=1 - needless to say, I was incredibly impressed!

I set about porting their code with very minimal tweaks into a reusable `BottomDrawer` component that had the various extra niceties I wanted: 

* Drag handle at the top
* Customizable open size / closed size
* Scrollable content area inside the sheet

After a good two hours of banging my head against the keyboard, I finally solved all the things I needed and created the following beautiful component (screenshot is at the top of this post). I call it `<BottomPanel>` - I know, so original - my excuse is I like to KISS.

To see a live working example of this component, head over to my website: 

> https://josiahbryan.com/#/bottompanel-demo

Example of `<BottomPanel>` closed:
![BottomPanel Closed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmu9y1t95cm44z6opqz1.png)

Example of `<BottomPanel>` open:
![BottomPanel Open](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqwfsos69pe1f8llg4mu.png)
Usable like this:

```
<BottomPanel
	maxOpenHeight={window.innerHeight * 0.8} // px
	closedPanelSize={200} // px
>
	<LoremIpsum />
</BottomPanel>
```

You can find the full source for `BottomPanel.jsx` and the required styles (`BottomPanel.module.scss`) in the following gist:
https://gist.github.com/josiahbryan/c220708256f7c8d79760aff37f64948f.

Cheers!
-Josiah Bryan